This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
#include "utils/assert.hpp"
|
||||
|
||||
#include "config.hpp"
|
||||
#include "service_runner.hpp"
|
||||
#include "server_env_manager.hpp"
|
||||
#include "templates.hpp"
|
||||
#include "services.hpp"
|
||||
@@ -19,6 +18,75 @@
|
||||
#include "command_registry.hpp"
|
||||
#include "shared_commands.hpp"
|
||||
|
||||
|
||||
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
|
||||
|
||||
class service_runner {
|
||||
public:
|
||||
service_runner(const std::string& server_name, const std::string& service_name);
|
||||
bool isValid() const { return mValid; }
|
||||
|
||||
// run a command over ssh, using the credentials from server.env (via server_env.hpp)
|
||||
// first check that the command corresponds to a valid .sh file in the service directory
|
||||
// then run the command, passing the {service_name}.env file as an argument
|
||||
// do a lot of checks, such as:
|
||||
// checking that we can ssh to the server.
|
||||
// checking whether the service directory exists on the server.
|
||||
// checking that the command exists in the service directory.
|
||||
// checking that the command is a valid .sh file.
|
||||
// checking that the {service_name}.env file exists in the service directory.
|
||||
bool run_command(const std::string& command, std::vector<std::string> additional_args={}, std::map<std::string, std::string> env_vars={});
|
||||
|
||||
// check health of service. Silent.
|
||||
// 1. run status.sh on the server
|
||||
// 2. return the output of the status.sh script
|
||||
|
||||
//HealthStatus is_healthy();
|
||||
|
||||
// std::string healthtick();
|
||||
// std::string healthmark();
|
||||
|
||||
public:
|
||||
// backup and restore
|
||||
bool backup(bool silent=false);
|
||||
bool restore(std::string backup_file, bool silent=false);
|
||||
|
||||
// nuke the service
|
||||
bool nuke(bool silent=false); // nukes all data for this service on the remote server
|
||||
bool fullnuke(); // nuke all data for this service on the remote server, and then nukes all the local service definitionfiles
|
||||
|
||||
// launch an interactive ssh session on a server or service
|
||||
// replaces the current dropshell process with the ssh process
|
||||
bool interactive_ssh_service();
|
||||
|
||||
bool scp_file_to_remote(const std::string& local_path, const std::string& remote_path, bool silent=false);
|
||||
bool scp_file_from_remote(const std::string& remote_path, const std::string& local_path, bool silent=false);
|
||||
public:
|
||||
// utility functions
|
||||
static std::string get_latest_backup_file(const std::string& server, const std::string& service);
|
||||
static bool interactive_ssh(const std::string & server_name, const std::string & command);
|
||||
// static std::map<std::string, ServiceStatus> get_all_services_status(std::string server_name);
|
||||
|
||||
private:
|
||||
std::string mServer;
|
||||
server_env_manager mServerEnv;
|
||||
LocalServiceInfo mServiceInfo;
|
||||
std::string mService;
|
||||
bool mValid;
|
||||
|
||||
// Helper methods
|
||||
public:
|
||||
};
|
||||
|
||||
|
||||
} // namespace dropshell
|
||||
|
||||
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace dropshell {
|
||||
@@ -165,58 +233,6 @@ bool service_runner::run_command(const std::string& command, std::vector<std::st
|
||||
}
|
||||
|
||||
|
||||
std::map<std::string, ServiceStatus> service_runner::get_all_services_status(std::string server_name)
|
||||
{
|
||||
std::map<std::string, ServiceStatus> status;
|
||||
|
||||
server_env_manager env(server_name);
|
||||
if (!env.is_valid()) {
|
||||
std::cerr << "Error: Invalid server environment" << std::endl;
|
||||
return status;
|
||||
}
|
||||
|
||||
std::string output;
|
||||
if (!execute_ssh_command(env.get_SSH_INFO(), sCommand(remotepath::agent(server_name), "./_allservicesstatus.sh", {
|
||||
{"HOST_NAME", server_name},
|
||||
{"SERVER",server_name},
|
||||
{"AGENT_PATH", remotepath::agent(server_name)}
|
||||
}), cMode::CaptureOutput, &output))
|
||||
return status;
|
||||
|
||||
std::stringstream ss(output);
|
||||
std::string line;
|
||||
while (std::getline(ss, line)) {
|
||||
std::string key, value;
|
||||
std::size_t pos = line.find("=");
|
||||
if (pos != std::string::npos) {
|
||||
key = dequote(trim(line.substr(0, pos)));
|
||||
value = dequote(trim(line.substr(pos + 1)));
|
||||
|
||||
// decode key, it's of format SERVICENAME_[HEALTH|PORTS]
|
||||
std::string service_name = key.substr(0, key.find_last_of("_"));
|
||||
std::string status_type = key.substr(key.find_last_of("_") + 1);
|
||||
|
||||
if (status_type == "HEALTH") { // healthy|unhealthy|unknown
|
||||
if (value == "healthy")
|
||||
status[service_name].health = HealthStatus::HEALTHY;
|
||||
else if (value == "unhealthy")
|
||||
status[service_name].health = HealthStatus::UNHEALTHY;
|
||||
else if (value == "unknown")
|
||||
status[service_name].health = HealthStatus::UNKNOWN;
|
||||
else
|
||||
status[service_name].health = HealthStatus::ERROR;
|
||||
} else if (status_type == "PORTS") { // port1,port2,port3
|
||||
std::vector<std::string> ports = string2multi(value);
|
||||
for (const auto& port : ports) {
|
||||
if (port!="unknown")
|
||||
status[service_name].ports.push_back(str2int(port));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
bool service_runner::interactive_ssh(const std::string & server_name, const std::string & command) {
|
||||
std::string serverpath = localpath::server(server_name);
|
||||
@@ -342,7 +358,7 @@ bool service_runner::restore(std::string backup_file, bool silent)
|
||||
return false;
|
||||
}
|
||||
|
||||
cRemoteTempFolder remote_temp_folder(mServerEnv);
|
||||
shared_commands::cRemoteTempFolder remote_temp_folder(mServerEnv);
|
||||
mServerEnv.run_remote_template_command(mService, "restore", {}, silent, {{"BACKUP_FILE", remote_backup_file_path}, {"TEMP_DIR", remote_temp_folder.path()}});
|
||||
} // dtor of remote_temp_folder will clean up the temp folder on the server
|
||||
|
||||
@@ -449,7 +465,7 @@ bool service_runner::backup(bool silent) {
|
||||
ASSERT(3 == count_substring(magic_string, local_backup_file_path), "Invalid backup filename");
|
||||
|
||||
{ // Run backup script
|
||||
cRemoteTempFolder remote_temp_folder(mServerEnv);
|
||||
shared_commands::cRemoteTempFolder remote_temp_folder(mServerEnv);
|
||||
if (!mServerEnv.run_remote_template_command(mService, command, {}, silent, {{"BACKUP_FILE", remote_backup_file_path}, {"TEMP_DIR", remote_temp_folder.path()}})) {
|
||||
std::cerr << "Backup script failed on remote server: " << remote_backup_file_path << std::endl;
|
||||
return false;
|
||||
@@ -469,27 +485,6 @@ bool service_runner::backup(bool silent) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cRemoteTempFolder::cRemoteTempFolder(const server_env_manager &server_env) : mServerEnv(server_env)
|
||||
{
|
||||
std::string p = remotepath::temp_files(server_env.get_server_name()) + "/" + random_alphanumeric_string(10);
|
||||
std::string mkdir_cmd = "mkdir -p " + quote(p);
|
||||
if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("", mkdir_cmd, {}), cMode::Silent))
|
||||
std::cerr << "Failed to create temp directory on server" << std::endl;
|
||||
else
|
||||
mPath = p;
|
||||
}
|
||||
|
||||
cRemoteTempFolder::~cRemoteTempFolder()
|
||||
{
|
||||
std::string rm_cmd = "rm -rf " + quote(mPath);
|
||||
execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand("", rm_cmd, {}), cMode::Silent);
|
||||
}
|
||||
|
||||
std::string cRemoteTempFolder::path() const
|
||||
{
|
||||
return mPath;
|
||||
}
|
||||
|
||||
// Helper function to get the latest backup file for a given server and service
|
||||
std::string service_runner::get_latest_backup_file(const std::string& server, const std::string& service) {
|
||||
std::string local_backups_dir = gConfig().get_local_backup_path();
|
||||
|
Reference in New Issue
Block a user