This commit is contained in:
247
source/src/commands/shared_commands.cpp
Normal file
247
source/src/commands/shared_commands.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
#include "shared_commands.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
#include "server_env_manager.hpp"
|
||||
#include "directories.hpp"
|
||||
#include "services.hpp"
|
||||
#include "servers.hpp"
|
||||
|
||||
namespace dropshell
|
||||
{
|
||||
|
||||
namespace shared_commands
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// std_autocomplete : SHARED COMMAND
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void std_autocomplete(const CommandContext &ctx)
|
||||
{
|
||||
if (ctx.args.size() == 0)
|
||||
{ // just the command, no args yet.
|
||||
// list servers
|
||||
std::vector<ServerInfo> servers = get_configured_servers();
|
||||
for (const auto &server : servers)
|
||||
{
|
||||
std::cout << server.name << std::endl;
|
||||
}
|
||||
}
|
||||
else if (ctx.args.size() == 1)
|
||||
{
|
||||
// list services
|
||||
std::vector<LocalServiceInfo> services = get_server_services_info(ctx.args[0]);
|
||||
for (const auto &service : services)
|
||||
{
|
||||
std::cout << service.service_name << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// std_autocomplete_allowall : SHARED COMMAND
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void std_autocomplete_allowall(const CommandContext &ctx)
|
||||
{
|
||||
std_autocomplete(ctx);
|
||||
if (ctx.args.size() == 1)
|
||||
std::cout << "all" << std::endl;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// rsync_tree_to_remote : SHARED COMMAND
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool rsync_tree_to_remote(
|
||||
const std::string &local_path,
|
||||
const std::string &remote_path,
|
||||
server_env_manager &server_env,
|
||||
bool silent)
|
||||
{
|
||||
ASSERT(!local_path.empty() && !remote_path.empty(), "Local or remote path not specified. Can't rsync.");
|
||||
|
||||
std::string rsync_cmd = "rsync --delete --mkpath -zrpc -e 'ssh -p " + server_env.get_SSH_PORT() + "' " +
|
||||
quote(local_path + "/") + " " +
|
||||
quote(server_env.get_SSH_USER() + "@" + server_env.get_SSH_HOST() + ":" +
|
||||
remote_path + "/");
|
||||
return execute_local_command(rsync_cmd, nullptr, (silent ? cMode::Silent : cMode::Defaults));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// get_arch : SHARED COMMAND
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string get_arch()
|
||||
{
|
||||
// determine the architecture of the system
|
||||
std::string arch;
|
||||
#ifdef __aarch64__
|
||||
arch = "arm64";
|
||||
#elif __x86_64__
|
||||
arch = "amd64";
|
||||
#endif
|
||||
return arch;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// cRemoteTempFolder : SHARED CLASS
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// get_all_services_status : SHARED COMMAND
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::map<std::string, ServiceStatus> 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// healthtick : SHARED COMMAND
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string healthtick(const std::string &server, const std::string &service)
|
||||
{
|
||||
std::string green_tick = "\033[32m✓\033[0m";
|
||||
std::string red_cross = "\033[31m✗\033[0m";
|
||||
std::string yellow_exclamation = "\033[33m!\033[0m";
|
||||
std::string unknown = "\033[37m✓\033[0m";
|
||||
|
||||
HealthStatus status = is_healthy(server, service);
|
||||
if (status == HealthStatus::HEALTHY)
|
||||
return green_tick;
|
||||
else if (status == HealthStatus::UNHEALTHY)
|
||||
return red_cross;
|
||||
else if (status == HealthStatus::UNKNOWN)
|
||||
return unknown;
|
||||
else
|
||||
return yellow_exclamation;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// HealthStatus2String : SHARED COMMAND
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string HealthStatus2String(HealthStatus status)
|
||||
{
|
||||
if (status == HealthStatus::HEALTHY)
|
||||
return ":tick:";
|
||||
else if (status == HealthStatus::UNHEALTHY)
|
||||
return ":cross:";
|
||||
else if (status == HealthStatus::UNKNOWN)
|
||||
return ":greytick:";
|
||||
else if (status == HealthStatus::NOTINSTALLED)
|
||||
return ":warning:";
|
||||
else
|
||||
return ":error:";
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// is_healthy : SHARED COMMAND
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
HealthStatus is_healthy(const std::string &server, const std::string &service)
|
||||
{
|
||||
server_env_manager env(server);
|
||||
if (!env.is_valid())
|
||||
{
|
||||
std::cerr << "Error: Server service not initialized" << std::endl;
|
||||
return HealthStatus::ERROR;
|
||||
}
|
||||
|
||||
if (!env.check_remote_dir_exists(remotepath::service(server, service)))
|
||||
{
|
||||
return HealthStatus::NOTINSTALLED;
|
||||
}
|
||||
|
||||
std::string script_path = remotepath::service_template(server, service) + "/status.sh";
|
||||
if (!env.check_remote_file_exists(script_path))
|
||||
{
|
||||
return HealthStatus::UNKNOWN;
|
||||
}
|
||||
|
||||
// Run status script, does not display output.
|
||||
if (!env.run_remote_template_command(service, "status", {}, true, {}))
|
||||
return HealthStatus::UNHEALTHY;
|
||||
return HealthStatus::HEALTHY;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// healthmark : SHARED COMMAND
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string healthmark(const std::string &server, const std::string &service)
|
||||
{
|
||||
HealthStatus status = is_healthy(server, service);
|
||||
return HealthStatus2String(status);
|
||||
}
|
||||
|
||||
} // namespace shared_commands
|
||||
|
||||
} // namespace dropshell
|
||||
Reference in New Issue
Block a user