diff --git a/source/src/commands/list.cpp b/source/src/commands/list.cpp index b5a82d0..47ca8e2 100644 --- a/source/src/commands/list.cpp +++ b/source/src/commands/list.cpp @@ -83,7 +83,7 @@ void list_servers() { } tableprint tp("All DropShell Servers"); - tp.add_row({"Name", "Address", "User", "Health", "Ports"}); + tp.add_row({"Name", "Address", "User", "Agent", "Health", "Ports"}); typedef std::map tServiceStatusMap; @@ -166,17 +166,24 @@ void list_servers() { } // Only check service status if server is online and not disabled + bool agent_match = true; if (is_online && !is_disabled) { - std::map status = shared_commands::get_all_services_status(sup.server.get_server_name(),sup.user.user); + std::map status = shared_commands::get_all_services_status(sup.server.get_server_name(),sup.user.user, &agent_match); for (const auto& [service_name, service_status] : status) { ports_used.insert(service_status.ports.begin(), service_status.ports.end()); serviceticks += shared_commands::HealthStatus2String(service_status.health) + " "; } - for (const auto& port : ports_used) + for (const auto& port : ports_used) ports_used_str += std::to_string(port) + " "; } + + // Agent status column + std::string agent_status = ""; + if (is_online && !is_disabled) { + agent_status = agent_match ? ":tick:" : ":cross:"; + } // Add red cross to address if server is offline std::string address_display = sup.server.get_SSH_HOST(); @@ -193,7 +200,7 @@ void list_servers() { // critical section { std::lock_guard lock(tp_mutex); - tp.add_row({server_name_display, address_display, sup.user.user, serviceticks, ports_used_str}); + tp.add_row({server_name_display, address_display, sup.user.user, agent_status, serviceticks, ports_used_str}); ++checked; } // print out a tick character for each server checked. diff --git a/source/src/commands/shared_commands.cpp b/source/src/commands/shared_commands.cpp index cc53d43..9bafa64 100644 --- a/source/src/commands/shared_commands.cpp +++ b/source/src/commands/shared_commands.cpp @@ -154,20 +154,30 @@ namespace dropshell // get_all_services_status : SHARED COMMAND // Uses all_status.sh on the remote server to get status for all services in one SSH call // ------------------------------------------------------------------------------------------------ - std::map get_all_services_status(const ServerConfig & server_env) + std::map get_all_services_status(const ServerConfig & server_env, bool* agent_match) { std::map status; + bool all_match = true; + bool any_checked = false; for (const auto& user : server_env.get_users()) { - status.merge(get_all_services_status(server_env, user.user)); + bool user_match = false; + status.merge(get_all_services_status(server_env, user.user, &user_match)); + if (!user_match) all_match = false; + any_checked = true; } + // Only report match if we actually checked something and all matched + if (agent_match) *agent_match = (any_checked && all_match); return status; } - std::map get_all_services_status(const ServerConfig & server_env, std::string user) + std::map get_all_services_status(const ServerConfig & server_env, std::string user, bool* agent_match) { std::map status; std::string server_name = server_env.get_server_name(); + // Default to false (mismatch/unknown) - only set to true if we get explicit confirmation + if (agent_match) *agent_match = false; + // Run all_status.sh on the remote server to get all service statuses in one call std::string agent_path = remotepath(server_name, user).agent(); std::string script_path = agent_path + "/all_status.sh"; @@ -192,16 +202,12 @@ namespace dropshell try { nlohmann::json json_response = nlohmann::json::parse(output); - // Check agent hash match + // Check agent hash match - if field is missing, agent is too old (mismatch) if (json_response.contains("agent_match") && json_response["agent_match"].is_boolean()) { - if (!json_response["agent_match"].get()) { - std::string remote_hash = json_response.contains("agent_hash") ? - json_response["agent_hash"].get() : "unknown"; - warning << "Agent mismatch on " << server_name << " (remote: " << remote_hash.substr(0, 8) - << "..., expected: " << expected_hash.substr(0, 8) << "...)" << std::endl; - warning << "Run 'ds install " << server_name << "' to update the agent" << std::endl; - } + bool match = json_response["agent_match"].get(); + if (agent_match) *agent_match = match; } + // If agent_match field is missing, leave as false (old agent = needs update) if (!json_response.contains("services") || !json_response["services"].is_array()) { debug << "Invalid JSON response from all_status.sh" << std::endl; diff --git a/source/src/commands/shared_commands.hpp b/source/src/commands/shared_commands.hpp index 253cb94..30a13c7 100644 --- a/source/src/commands/shared_commands.hpp +++ b/source/src/commands/shared_commands.hpp @@ -68,8 +68,8 @@ namespace dropshell std::string get_arch(); - std::map get_all_services_status(const ServerConfig & server_env); - std::map get_all_services_status(const ServerConfig & server_env, std::string user); + std::map get_all_services_status(const ServerConfig & server_env, bool* agent_match = nullptr); + std::map get_all_services_status(const ServerConfig & server_env, std::string user, bool* agent_match = nullptr); std::string healthtick(const std::string &server, const std::string &service); std::string HealthStatus2String(HealthStatus status);