blob: efcd96f58d2fbb9a67bdfe8d33c1250e9d91d2bb [file] [log] [blame]
#ifndef INSTALL_INSTALLER_H_
#define INSTALL_INSTALLER_H_
#include <cstdint>
#include <fstream>
#include <optional>
#include <string>
#include <vector>
#include "absl/time/time.h"
#include "nlohmann/json.hpp"
namespace bloom_install {
// Represents a software package to be installed.
struct Package {
std::string name;
std::string activation_script_path;
std::string install_script_path;
bool operator==(const Package& other) const {
return name == other.name &&
activation_script_path == other.activation_script_path &&
install_script_path == other.install_script_path;
}
};
// Defines the possible states of the installation process for logging.
enum class State : std::uint8_t {
kStarting,
kCheckingActivation,
kSkipped,
kInstalling,
kSuccess,
kFailureRetry,
kFailureFatal,
kUnknown
};
// Defines the specific event codes for logging.
enum class LogCode : std::uint8_t {
kInitStart,
kInstallHalt,
kInstallComplete,
kPkgActivationCheckStart,
kPkgActivationSkip,
kPkgInstallProceed,
kPkgInstallStart,
kPkgInstallSuccess,
kPkgInstallFailRetry,
kPkgInstallFailFatal,
kUnknown
};
// Handles logging of installation progress to a file in JSON format.
class ProgressLogger {
public:
explicit ProgressLogger(const std::string& log_file_path);
// Logs a progress message using a type-safe LogCode enum.
void Log(State state, absl::Duration elapsed_time, const std::string& message,
LogCode code, int retries = -1);
bool IsHealthy() const;
private:
static std::string StateToString(State state) {
switch (state) {
case State::kStarting:
return "starting";
case State::kCheckingActivation:
return "checking_activation";
case State::kSkipped:
return "skipped";
case State::kInstalling:
return "installing";
case State::kSuccess:
return "success";
case State::kFailureRetry:
return "failure_retry";
case State::kFailureFatal:
return "failure_fatal";
default:
return "unknown";
}
}
// Converts a LogCode enum to its string representation.
static std::string LogCodeToString(LogCode code) {
switch (code) {
case LogCode::kInitStart:
return "init_start";
case LogCode::kInstallHalt:
return "install_halt";
case LogCode::kInstallComplete:
return "install_complete";
case LogCode::kPkgActivationCheckStart:
return "pkg_activation_check_start";
case LogCode::kPkgActivationSkip:
return "pkg_activation_skip";
case LogCode::kPkgInstallProceed:
return "pkg_install_proceed";
case LogCode::kPkgInstallStart:
return "pkg_install_start";
case LogCode::kPkgInstallSuccess:
return "pkg_install_success";
case LogCode::kPkgInstallFailRetry:
return "pkg_install_fail_retry";
case LogCode::kPkgInstallFailFatal:
return "pkg_install_fail_fatal";
default:
return "unknown";
}
}
std::string log_file_path_;
std::ofstream log_file_;
bool is_healthy_;
};
namespace internal {
// Reports generic installation status to a file.
// This class implements the contract between the installer and its consumers.
// Do not use this class directly.
class StatusReporter {
public:
static StatusReporter Create(const std::string& status_path,
int total_packages);
// Writes the initial "IN_PROGRESS" status.
void Start(const std::string& message);
// Records a successfully completed package and updates progress.
void RecordSuccess(const std::string& message);
// Finalizes the status file as "SUCCESS" or "FAILURE".
void Complete(bool success, const std::string& message);
private:
// Private constructor forces use of the factory method.
StatusReporter(const std::string& status_path, int total_packages);
// Writes the current state to the JSON file.
void WriteStatus();
// Updates the progress fields in the JSON object.
void UpdateProgress(const std::string& message);
std::string status_path_;
int total_packages_;
int packages_completed_ = 0;
nlohmann::json status_json_;
};
} // namespace internal
// Defines configuration options for the Installer.
struct InstallerOptions {
std::vector<Package> packages;
int max_retries = 3;
std::string log_path = "/var/google/install/progress_internal.log";
std::string status_path = "/var/google/install/progress_status.json";
// Activation check scripts will be persisted in this directory.
std::string activation_check_dir = "/var/google/firmware_bundle/";
};
// Manages the installation of a list of software packages.
class Installer {
public:
explicit Installer(const InstallerOptions& options);
// Post install runs the activation check and install scripts for each
// package. Returns true if all packages are installed successfully, false
// otherwise. It also persists the activation check scripts to the activation
// check directory.
bool PostInstall();
// Activation check runs the activation check scripts for each package.
void ActivationCheck();
private:
bool InstallPackage(const Package& package);
const InstallerOptions options_;
ProgressLogger logger_;
internal::StatusReporter status_reporter_;
};
std::vector<Package> ParsePostInstallPackages(const std::string& tar_file_path);
int ActivationMain(const std::string& activation_check_dir);
int PostInstallMain(const std::string& inventory_dir,
const std::string& install_lock_file_path,
const std::string& bundle_tar_file_path,
const std::string& activation_check_dir);
} // namespace bloom_install
#endif // INSTALL_INSTALLER_H_