#include "command_registry.hpp" #include "directories.hpp" #include "shared_commands.hpp" #include "templates.hpp" #include #include "utils/utils.hpp" #include "services.hpp" namespace dropshell { int uninstall_handler(const CommandContext &ctx); static std::vector uninstall_name_list = {"uninstall", "remove"}; // Static registration struct UninstallCommandRegister { UninstallCommandRegister() { CommandRegistry::instance().register_command({uninstall_name_list, uninstall_handler, shared_commands::std_autocomplete_allowall, false, // hidden true, // requires_config true, // requires_install 2, // min_args (after command) 2, // max_args (after command) "uninstall SERVER SERVICE|all", "Uninstall a service on a server. Does not remove configuration or user data.", // heredoc R"( Uninstall a service, leaving all configuration and data intact. uninstall SERVER SERVICE Uninstall the given service on the given server. uninstall SERVER all Uninstall all services on the given server. Update and reinstall the service with install, or delete all configuration and data with destroy. )"}); } } uninstall_command_register; namespace shared_commands { bool uninstall_service(const ServerConfig & server_env, const std::string &service) { ASSERT(server_env.is_valid(), "Invalid server environment for " + server_env.get_server_name()); std::string server = server_env.get_server_name(); maketitle("Uninstalling " + service + " on " + server); std::string user = server_env.get_user_for_service(service); // 2. Check if service directory exists on server if (!server_env.check_remote_dir_exists(remotepath(server, user).service(service), user)) { error << "Service is not installed: " << service << std::endl; return true; // Nothing to uninstall } // 3. Run uninstall script if it exists std::string uninstall_script = remotepath(server, user).service_template(service) + "/uninstall.sh"; if (!server_env.run_remote_template_command(service, "uninstall", {}, false, {})) warning << "Uninstall script failed, but continuing with directory removal" << std::endl; // 4. Remove the service directory from the server, running in a docker container as root. if (server_env.remove_remote_dir(remotepath(server, user).service(service), false, user)) { ASSERT(!server_env.check_remote_dir_exists(remotepath(server, user).service(service), user), "Service directory still found on server after uninstall"); info << "Removed remote service directory " << remotepath(server, user).service(service) << std::endl; } else warning << "Failed to remove remote service directory" << std::endl; info << "Completed service " << service << " uninstall on " << server << std::endl; return true; } } // namespace shared_commands int uninstall_handler(const CommandContext &ctx) { if (ctx.args.size() < 1) { error << "uninstall requires a server and a service (or all)" << std::endl; return 1; } std::string server = safearg(ctx.args, 0); if (safearg(ctx.args, 1) == "all") { // uninstall all services on the server bool okay = true; std::vector services = get_server_services_info(server); for (const auto &service : services) { if (!shared_commands::uninstall_service(server, service.service_name)) okay = false; } return okay ? 0 : 1; } std::string service = safearg(ctx.args, 1); return shared_commands::uninstall_service(server, service) ? 0 : 1; } } // namespace dropshell