198 lines
6.2 KiB
C++
198 lines
6.2 KiB
C++
#include "servers.hpp"
|
|
#include "server_env.hpp"
|
|
#include "service_runner.hpp"
|
|
#include "tableprint.hpp"
|
|
#include "interactive/interactive.hpp"
|
|
#include "utils/envmanager.hpp"
|
|
#include "utils/directories.hpp"
|
|
#include "services.hpp"
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <iomanip>
|
|
#include <boost/filesystem.hpp>
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
namespace fs = boost::filesystem;
|
|
|
|
namespace dropshell {
|
|
|
|
std::vector<ServerInfo> get_configured_servers() {
|
|
std::vector<ServerInfo> servers;
|
|
|
|
std::string servers_dir = get_local_config_servers_path();
|
|
if (servers_dir.empty()) {
|
|
return servers;
|
|
}
|
|
|
|
if (!fs::exists(servers_dir)) {
|
|
std::cerr << "Error: Servers directory not found:" << servers_dir << std::endl;
|
|
return servers;
|
|
}
|
|
|
|
for (const auto& entry : fs::directory_iterator(servers_dir)) {
|
|
if (fs::is_directory(entry)) {
|
|
std::string server_name = entry.path().filename().string();
|
|
|
|
server_env env(server_name);
|
|
if (!env.is_valid()) {
|
|
std::cerr << "Error: Invalid server environment file: " << server_name << std::endl;
|
|
continue;
|
|
}
|
|
servers.push_back({
|
|
server_name,
|
|
env.get_SSH_HOST(),
|
|
env.get_SSH_USER(),
|
|
env.get_SSH_PORT()
|
|
});
|
|
}
|
|
}
|
|
|
|
return servers;
|
|
}
|
|
|
|
|
|
|
|
void list_servers() {
|
|
auto servers = get_configured_servers();
|
|
|
|
tableprint tp("All DropShell Servers");
|
|
tp.add_row({"Name", "Address", "Health", "Ports"});
|
|
for (const auto& server : servers) {
|
|
std::vector<int> ports_used;
|
|
std::string serviceticks = "";
|
|
std::vector<ServiceInfo> services = get_server_services_info(server.name);
|
|
for (const auto& service : services) {
|
|
service_runner ss;
|
|
if (ss.init(server.name, service.service_name))
|
|
serviceticks += ss.healthmark() + " ";
|
|
else std::cout<<"Error: Failed to initialise service runner for server: ["<<server.name<<"] and service: ["<<service.service_name<<"]"<<std::endl;
|
|
std::vector<int> ports = ss.get_ports();
|
|
ports_used.insert(ports_used.end(), ports.begin(), ports.end());
|
|
}
|
|
// convert ports_used to string
|
|
std::string ports_used_str = "";
|
|
bool first = true;
|
|
for (const auto& port : ports_used) {
|
|
if (!first) {
|
|
ports_used_str += ", ";
|
|
}
|
|
ports_used_str += std::to_string(port);
|
|
first = false;
|
|
}
|
|
tp.add_row({server.name, server.ssh_host, serviceticks, ports_used_str});
|
|
}
|
|
tp.print();
|
|
}
|
|
|
|
void show_server_details(const std::string& server_name) {
|
|
server_env env(server_name);
|
|
if (!env.is_valid()) {
|
|
std::cerr << "Error: Invalid server environment file: " << server_name << std::endl;
|
|
return;
|
|
}
|
|
|
|
//---------------------
|
|
// Check if server is reachable via SSH
|
|
std::string ssh_address = env.get_SSH_HOST();
|
|
std::string ssh_user = env.get_SSH_USER();
|
|
std::string ssh_port = env.get_SSH_PORT();
|
|
if (!ssh_address.empty()) {
|
|
std::cout << std::endl << "Server Status:" << std::endl;
|
|
std::cout << std::string(40, '-') << std::endl;
|
|
|
|
// Try to connect to the server
|
|
std::string cmd = "ssh -o ConnectTimeout=5 " + ssh_user + "@" + ssh_address + " -p " + ssh_port + " 'echo connected' 2>/dev/null";
|
|
int result = system(cmd.c_str());
|
|
if (result == 0) {
|
|
std::cout << "Status: Online" << std::endl;
|
|
|
|
// // Get uptime if possible
|
|
// cmd = "ssh " + ssh_address + " 'uptime' 2>/dev/null";
|
|
// int rval = system(cmd.c_str());
|
|
// if (rval != 0) {
|
|
// std::cout << "Error: Failed to get uptime" << std::endl;
|
|
// }
|
|
} else {
|
|
std::cout << "Status: Offline" << std::endl;
|
|
}
|
|
}
|
|
std::cout << std::endl;
|
|
|
|
//---------------------
|
|
{
|
|
std::cout << std::endl;
|
|
tableprint tp("Server Configuration: " + server_name, true);
|
|
tp.add_row({"Key", "Value"});
|
|
for (const auto& [key, value] : env.get_variables()) {
|
|
tp.add_row({key, value});
|
|
}
|
|
tp.print();
|
|
}
|
|
|
|
//---------------------
|
|
// list services, and run healthcheck on each
|
|
{
|
|
tableprint tp("Services: " + server_name, false);
|
|
tp.add_row({"Status", "Service", "Ports"});
|
|
|
|
std::vector<ServiceInfo> services = get_server_services_info(server_name);
|
|
for (const auto& service : services) {
|
|
std::string healthy = "?";
|
|
std::vector<int> ports;
|
|
service_runner ss;
|
|
if (ss.init(server_name, service.service_name))
|
|
{
|
|
healthy = ss.healthmark();
|
|
ports = ss.get_ports();
|
|
}
|
|
bool first = true;
|
|
std::string ports_str = "";
|
|
for (const auto& port : ports) {
|
|
if (!first) {
|
|
ports_str += ", ";
|
|
}
|
|
ports_str += std::to_string(port);
|
|
first = false;
|
|
}
|
|
tp.add_row({healthy, service.service_name, ports_str});
|
|
} // end of for (const auto& service : services)
|
|
tp.print();
|
|
} // end of list services
|
|
} // end of show_server_details
|
|
|
|
|
|
|
|
|
|
|
|
void interactive_mode() {
|
|
interactive::fullscreen_window iw("DropShell Servers");
|
|
|
|
iw.set_input_text_display("Loading all servers' status...");
|
|
|
|
auto servers = get_configured_servers();
|
|
std::vector<std::string> server_names;
|
|
for (const auto& server : servers) {
|
|
server_names.push_back(server.name);
|
|
}
|
|
|
|
list_servers();
|
|
|
|
while (true) {
|
|
std::string server_name = iw.set_input_multiple_choice("Select a server", server_names);
|
|
if (server_name.empty())
|
|
{
|
|
iw.close();
|
|
return;
|
|
}
|
|
|
|
while (!server_name.empty()) {
|
|
iw.clear_display();
|
|
show_server_details(server_name);
|
|
server_name = iw.set_input_multiple_choice("Select a server", server_names, server_name);
|
|
}
|
|
iw.clear_display();
|
|
list_servers();
|
|
}
|
|
}
|
|
|
|
} // namespace dropshell
|