180 lines
8.4 KiB
C++
180 lines
8.4 KiB
C++
#include "command_registry.hpp"
|
|
#include "shared_commands.hpp"
|
|
#include "config.hpp"
|
|
#include "services.hpp"
|
|
#include "servers.hpp"
|
|
#include "utils/directories.hpp"
|
|
#include "servers.hpp"
|
|
#include "templates.hpp"
|
|
#include "utils/utils.hpp"
|
|
|
|
#include <libassert/assert.hpp>
|
|
|
|
namespace dropshell
|
|
{
|
|
|
|
int destroy_handler(const CommandContext &ctx);
|
|
static std::vector<std::string> destroy_name_list = {"destroy", "nuke", "nuke-service","erase","destroy-service"};
|
|
|
|
// Static registration
|
|
struct DestroyCommandRegister
|
|
{
|
|
DestroyCommandRegister()
|
|
{
|
|
CommandRegistry::instance().register_command({destroy_name_list,
|
|
destroy_handler,
|
|
shared_commands::std_autocomplete,
|
|
false, // hidden
|
|
true, // requires_config
|
|
true, // requires_install
|
|
2, // min_args (after command)
|
|
2, // max_args (after command)
|
|
"destroy SERVER SERVICE|all",
|
|
"Destroy a service on a server. Erases everything, both local and remote!",
|
|
// heredoc
|
|
R"(
|
|
Destroy a service.
|
|
|
|
Examples:
|
|
destroy SERVER SERVICE destroy the given service on the given server.
|
|
destroy SERVER all destroy all services on the given server.
|
|
|
|
Note: This command is destructive and will destroy all data and all configuration,
|
|
both on the dropshell host and on the remote server.
|
|
|
|
Use with caution!
|
|
)"});
|
|
}
|
|
} destroy_command_register;
|
|
|
|
namespace shared_commands
|
|
{
|
|
|
|
bool destroy_service(const std::string &server, const std::string &service)
|
|
{
|
|
ServerConfig server_env(server);
|
|
|
|
// step 1 - destroy on remote server.
|
|
if (server_env.is_valid())
|
|
{
|
|
std::string user = server_env.get_user_for_service(service); // returns empty string if no user found.
|
|
if (user.empty())
|
|
{
|
|
warning << "No user found for service " << service << " on " << server << std::endl;
|
|
for (auto sshuser : server_env.get_users())
|
|
{
|
|
if (server_env.check_remote_dir_exists(remotepath(server, sshuser.user).service(service), sshuser.user))
|
|
{
|
|
info << "Found a remote service directory here: " << remotepath(server, sshuser.user).service(service) << std::endl;
|
|
info << "Deleting it as user " << sshuser.user << std::endl;
|
|
user = sshuser.user;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (user.empty())
|
|
warning << "No remote service directory found for " << service << " on " << server << std::endl;
|
|
else
|
|
{ // user is not empty.
|
|
LocalServiceInfo service_info;
|
|
service_info = get_service_info(server, service);
|
|
bool service_valid = SIvalid(service_info);
|
|
if (!service_valid)
|
|
warning << "No valid service definition found for " << service << std::endl;
|
|
|
|
if (server_env.check_remote_dir_exists(remotepath(server, user).service(service), user))
|
|
{
|
|
// run the destroy script on the remote server if it exists.
|
|
// otherwise just uninstall.
|
|
if (service_valid)
|
|
{
|
|
if (gTemplateManager().template_command_exists(service_info.template_name, "destroy"))
|
|
{
|
|
info << "Running destroy script for " << service << " on " << server << std::endl;
|
|
if (!server_env.run_remote_template_command(service, "destroy", {}, false, {}))
|
|
warning << "Failed to run destroy script: " << service << std::endl;
|
|
}
|
|
else
|
|
{
|
|
info << "No destroy script found for " << service << " on " << server << std::endl;
|
|
info << "Running uninstall script instead and will clean directories." << std::endl;
|
|
if (!server_env.run_remote_template_command(service, "uninstall", {}, false, {}))
|
|
warning << "Failed to uninstall service: " << service << std::endl;
|
|
}
|
|
}
|
|
|
|
// 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), true, user))
|
|
{
|
|
ASSERT(!server_env.check_remote_dir_exists(remotepath(server, user).service(service), user), "Service directory still found on server after uninstall");
|
|
info << "Remote service directory removed: " << remotepath(server, user).service(service) << std::endl;
|
|
}
|
|
else
|
|
warning << "Failed to remove remote service directory" << std::endl;
|
|
}
|
|
else
|
|
warning << "No remote service directory found for " << service << " on "<< server << std::endl;
|
|
} // user is not empty.
|
|
} // server_env is valid.
|
|
else
|
|
error << "No valid local server information for server " << server << std::endl;
|
|
|
|
// step 2 - destroy the local service directory, if it exists.
|
|
std::string local_service_path = localpath::service(server, service);
|
|
if (local_service_path.empty() || !std::filesystem::exists(local_service_path))
|
|
{
|
|
warning << "No local service directory found for " << service << " on " << server << std::endl;
|
|
}
|
|
else
|
|
{
|
|
auto itemsdeleted = std::filesystem::remove_all(local_service_path);
|
|
if (itemsdeleted == 0)
|
|
error << "Failed to remove local service directory" << std::endl;
|
|
else
|
|
info << "Local service directory removed: " << local_service_path << std::endl;
|
|
}
|
|
|
|
info << "Finished destroying service " << service << " on server " << server << std::endl;
|
|
|
|
return true;
|
|
}
|
|
} // namespace shared_commands
|
|
|
|
int destroy_handler(const CommandContext &ctx)
|
|
{
|
|
ASSERT(ctx.args.size() == 2, "Usage: destroy SERVER SERVICE|all (requires 2 args - you supplied " + std::to_string(ctx.args.size()) + ")");
|
|
ASSERT(gConfig().is_config_set(), "No configuration found. Please run 'dropshell config' to set up your configuration.");
|
|
|
|
std::string server = safearg(ctx.args, 0);
|
|
std::string service = safearg(ctx.args, 1);
|
|
|
|
if (service == "all")
|
|
{
|
|
int rval = 0;
|
|
|
|
// iterate through all service folders in the server directory.
|
|
std::string server_path = localpath::server(server);
|
|
if (server_path.empty())
|
|
{
|
|
error << "Server not found: " << server << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
for (const auto &entry : std::filesystem::directory_iterator(server_path))
|
|
{
|
|
if (entry.is_directory() && entry.path().filename().string().find(".") != 0)
|
|
{
|
|
std::string service_name = entry.path().filename().string();
|
|
rval |= (shared_commands::destroy_service(server, service_name) ? 0 : 1);
|
|
}
|
|
}
|
|
return rval;
|
|
}
|
|
else
|
|
{
|
|
return (shared_commands::destroy_service(server, service) ? 0 : 1);
|
|
}
|
|
}
|
|
|
|
} // namespace dropshell
|