docs: Add 2 and update 2 files
All checks were successful
Build-Test-Publish / build (linux/amd64) (push) Successful in 34s
Build-Test-Publish / build (linux/arm64) (push) Successful in 1m18s

This commit is contained in:
j
2026-02-21 22:21:03 +13:00
parent ea1004dd7e
commit fdde0bc774
4 changed files with 286 additions and 2 deletions

View File

@@ -0,0 +1,171 @@
#include "command_registry.hpp"
#include "servers.hpp"
#include "utils/output.hpp"
#include "utils/execute.hpp"
#include "utils/directories.hpp"
#include "shared_commands.hpp"
#include "tableprint.hpp"
#include <nlohmann/json.hpp>
#include <libassert/assert.hpp>
#include <cstdio>
namespace dropshell {
int hostinfo_handler(const CommandContext &ctx);
static std::vector<std::string> hostinfo_name_list = {"hostinfo", "sysinfo"};
void hostinfo_autocomplete(const CommandContext &ctx) {
if (ctx.args.size() == 0) {
std::vector<ServerConfig> servers = get_configured_servers();
for (const auto &server : servers)
rawout << server.get_server_name() << std::endl;
}
}
struct HostinfoCommandRegister {
HostinfoCommandRegister() {
CommandRegistry::instance().register_command({
hostinfo_name_list,
hostinfo_handler,
hostinfo_autocomplete,
false, // hidden
true, // requires_config
true, // requires_install
1, // min_args
1, // max_args
"hostinfo SERVER",
"Display hardware and system information for a remote server.",
R"(
Display hardware and system information for a remote server.
hostinfo SERVER Show CPU, motherboard, GPU, RAM, disk usage,
IP addresses, OS, kernel, uptime, and Docker version.
)"
});
}
} hostinfo_command_register;
int hostinfo_handler(const CommandContext &ctx) {
std::string server_name = ctx.args[0];
ServerConfig server_env(server_name);
if (!server_env.is_valid()) {
error << "Server '" << server_name << "' is not valid." << std::endl;
return 1;
}
ASSERT(server_env.get_users().size() > 0, "No users found for server " + server_name);
std::string user = server_env.get_users()[0].user;
std::string agent_path = remotepath(server_name, user).agent();
std::string script_path = agent_path + "/hostinfo.sh";
std::string output;
sCommand cmd(agent_path, script_path, {});
bool success = execute_ssh_command(server_env.get_SSH_INFO(user), cmd, cMode::Silent, &output);
if (!success || output.empty()) {
error << "Failed to retrieve host information from " << server_name << std::endl;
return 1;
}
nlohmann::json j;
try {
j = nlohmann::json::parse(output);
} catch (const nlohmann::json::parse_error &e) {
error << "Failed to parse host info: " << e.what() << std::endl;
debug << "Output was: " << output << std::endl;
return 1;
}
auto get_str = [&](const std::string &key) -> std::string {
if (j.contains(key) && j[key].is_string()) {
std::string val = j[key].get<std::string>();
return val.empty() ? "-" : val;
}
return "-";
};
// Format RAM as "X.X / Y.Y GB"
std::string ram_display = "-";
{
std::string used = get_str("ram_used_mb");
std::string total = get_str("ram_total_mb");
if (used != "-" && total != "-") {
try {
int used_mb = std::stoi(used);
int total_mb = std::stoi(total);
char buf[64];
snprintf(buf, sizeof(buf), "%.1f / %.1f GB",
used_mb / 1024.0, total_mb / 1024.0);
ram_display = buf;
} catch (...) {}
}
}
// Format disk root
std::string disk_root_display = "-";
{
std::string used = get_str("disk_root_used_gb");
std::string total = get_str("disk_root_total_gb");
if (used != "-" && total != "-")
disk_root_display = used + " / " + total + " GB";
}
// Format disk /tank (only if present)
std::string disk_tank_display;
{
std::string used = get_str("disk_tank_used_gb");
std::string total = get_str("disk_tank_total_gb");
if (used != "-" && total != "-")
disk_tank_display = used + " / " + total + " GB";
}
// Format GPU list
std::string gpu_display = "-";
if (j.contains("gpu") && j["gpu"].is_array() && !j["gpu"].empty()) {
gpu_display.clear();
for (size_t i = 0; i < j["gpu"].size(); ++i) {
if (i > 0) gpu_display += ", ";
gpu_display += j["gpu"][i].get<std::string>();
}
}
// Format CPU with cores
std::string cpu_display = get_str("cpu");
std::string cores = get_str("cpu_cores");
if (cores != "-")
cpu_display += " (" + cores + " cores)";
// Format IP addresses on one line
std::string ip_display = get_str("ip_local");
{
std::string ts = get_str("ip_tailscale");
std::string pub = get_str("ip_public");
if (ts != "-") ip_display += " ts:" + ts;
if (pub != "-") ip_display += " pub:" + pub;
}
// Display
tableprint tp("Host Info: " + server_name, true);
tp.add_row({"Property", "Value"});
tp.add_row({"Hostname", get_str("hostname")});
tp.add_row({"OS", get_str("os")});
tp.add_row({"Kernel", get_str("kernel")});
tp.add_row({"Uptime", get_str("uptime")});
tp.add_row({"CPU", cpu_display});
tp.add_row({"Motherboard", get_str("motherboard")});
tp.add_row({"GPU", gpu_display});
tp.add_row({"RAM", ram_display});
tp.add_row({"Disk /", disk_root_display});
if (!disk_tank_display.empty())
tp.add_row({"Disk /tank", disk_tank_display});
tp.add_row({"IP Addresses", ip_display});
tp.add_row({"Docker", get_str("docker_version")});
tp.print();
return 0;
}
} // namespace dropshell