Better errors.

This commit is contained in:
Your Name 2025-05-05 23:37:14 +12:00
parent 42e25b6353
commit 38cb23706d
7 changed files with 87 additions and 25 deletions

View File

@ -231,15 +231,19 @@ int main(int argc, char* argv[]) {
// run the command on each service.
for (const auto& service_info : server_and_services.servicelist) {
service_runner runner(server_and_services.server_name, service_info.service_name);
if (!runner.isValid())
return die("Error: Failed to initialize service");
std::vector<std::string> additional_args;
for (int i=4; i<argc; i++)
additional_args.push_back(argv[i]);
if (!runner.run_command(cmd, additional_args))
return die(cmd+" failed.");
if (!SIvalid(service_info))
std::cerr<<"Error: Unable to get service information."<<std::endl;
else {
service_runner runner(server_and_services.server_name, service_info.service_name);
if (!runner.isValid())
return die("Error: Failed to initialize service");
std::vector<std::string> additional_args;
for (int i=4; i<argc; i++)
additional_args.push_back(argv[i]);
if (!runner.run_command(cmd, additional_args))
return die(cmd+" failed on service "+service_info.service_name);
}
}
// success!

View File

@ -112,13 +112,19 @@ std::string server_env_manager::construct_ssh_cmd(bool allocateTTY) const {
sCommand server_env_manager::construct_standard_command_run_cmd(const std::string &service_name, const std::string &command, std::vector<std::string> args, bool silent) const
{
if (command.empty())
return sCommand();
std::string remote_service_template_path = remotepath::service_template(mServerName,service_name);
std::string remote_service_config_path = remotepath::service_config(mServerName,service_name);
std::string script_path = remote_service_template_path + "/" + command + ".sh";
std::map<std::string, std::string> env_vars;
get_all_service_env_vars(mServerName, service_name, env_vars);
if (!get_all_service_env_vars(mServerName, service_name, env_vars)) {
std::cerr << "Error: Failed to get all service env vars for " << service_name << std::endl;
return sCommand();
}
std::string argstr = "";
for (const auto& arg : args) {
@ -126,6 +132,10 @@ sCommand server_env_manager::construct_standard_command_run_cmd(const std::strin
}
sCommand scommand(remote_service_template_path, "bash " + quote(script_path) + argstr + (silent ? " > /dev/null 2>&1" : ""), env_vars);
if (scommand.empty())
std::cerr << "Error: Failed to construct command for " << service_name << " " << command << std::endl;
return scommand;
}
@ -187,6 +197,8 @@ bool server_env_manager::execute_ssh_command_and_capture_output(const sCommand&
bool server_env_manager::run_remote_template_command(const std::string &service_name, const std::string &command, std::vector<std::string> args, bool silent) const
{
sCommand scommand = construct_standard_command_run_cmd(service_name, command, args, silent);
if (scommand.get_command_to_run().empty())
return false;
bool allocateTTY = (command=="ssh");
return execute_ssh_command(scommand, allocateTTY);
}
@ -194,17 +206,23 @@ bool server_env_manager::run_remote_template_command(const std::string &service_
bool server_env_manager::run_remote_template_command_and_capture_output(const std::string &service_name, const std::string &command, std::vector<std::string> args, std::string &output, bool silent) const
{
sCommand scommand = construct_standard_command_run_cmd(service_name, command, args, silent);
if (scommand.get_command_to_run().empty())
return false;
bool allocateTTY = (command=="ssh");
return execute_ssh_command_and_capture_output(scommand, output, allocateTTY);
}
bool server_env_manager::execute_local_command(const sCommand& command) {
if (command.get_command_to_run().empty())
return false;
int ret = system(command.construct_safecmd().c_str());
return EXITSTATUSCHECK(ret);
}
bool server_env_manager::execute_local_command_interactive(const sCommand &command)
{
if (command.get_command_to_run().empty())
return false;
std::string full_command = command.construct_rawcmd(); // Get the command string
pid_t pid = fork();
@ -237,6 +255,8 @@ bool server_env_manager::execute_local_command_interactive(const sCommand &comma
bool server_env_manager::execute_local_command_and_capture_output(const sCommand& command, std::string &output)
{
if (command.get_command_to_run().empty())
return false;
std::string full_cmd = command.construct_safecmd() + " 2>&1";
FILE *pipe = popen(full_cmd.c_str(), "r");
if (!pipe) {
@ -253,6 +273,8 @@ bool server_env_manager::execute_local_command_and_capture_output(const sCommand
std::string sCommand::construct_safecmd() const
{
if (mCmd.empty())
return "";
std::string to_encode;
for (const auto& env_var : mVars) {
@ -271,6 +293,9 @@ std::string sCommand::construct_safecmd() const
std::string sCommand::construct_rawcmd() const
{
if (mCmd.empty())
return "";
std::string rawcmd;
if (!mDir.empty())
rawcmd = "cd " + quote(mDir) + " && ";
@ -287,6 +312,8 @@ std::string sCommand::construct_rawcmd() const
std::string makesafecmd(const std::string &command)
{
if (command.empty())
return "";
std::string encoded = base64_encode(dequote(trim(command)));
std::string commandstr = "echo " + encoded + " | base64 -d | bash";
return commandstr;

View File

@ -18,7 +18,7 @@ class sCommand {
mDir(directory_to_run_in), mCmd(command_to_run), mVars(env_vars) {}
sCommand(std::string command_to_run) :
mDir(""), mCmd(command_to_run), mVars({}) {}
sCommand() : mDir(""), mCmd(""), mVars({}) {}
std::string get_directory_to_run_in() const { return mDir; }
std::string get_command_to_run() const { return mCmd; }
@ -29,6 +29,8 @@ class sCommand {
std::string construct_safecmd() const;
std::string construct_rawcmd() const;
bool empty() const { return mCmd.empty(); }
private:
std::string mDir;
std::string mCmd;

View File

@ -31,6 +31,9 @@ service_runner::service_runner(const std::string& server_name, const std::string
return;
mServiceInfo = get_service_info(server_name, service_name);
if (mServiceInfo.service_name.empty())
return;
mService = mServiceInfo.service_name;
mValid = !mServiceInfo.local_template_path.empty();
@ -144,7 +147,7 @@ bool service_runner::uninstall() {
return true;
}
bool service_runner::nuke()
bool service_runner::nuke(bool silent)
{
maketitle("Nuking " + mService + " (" + mServiceInfo.template_name + ") on " + mServer);
@ -180,16 +183,17 @@ bool service_runner::nuke()
std::cout << "Service " << mService << " successfully nuked from " << mServer << std::endl;
std::cout << "There's nothing left on the remote server." << std::endl;
std::cout << "You can remove the local files with:" << std::endl;
std::cout << " rm -rf " << localpath::service(mServer,mService) << std::endl;
if (!silent) {
std::cout << "There's nothing left on the remote server." << std::endl;
std::cout << "You can remove the local files with:" << std::endl;
std::cout << " rm -rf " << localpath::service(mServer,mService) << std::endl;
}
return true;
}
bool service_runner::fullnuke()
{
if (!nuke())
if (!nuke(true))
{
std::cerr << "Warning: Nuke script failed, aborting fullnuke!" << std::endl;
return false;

View File

@ -78,7 +78,7 @@ class service_runner {
bool restore(std::string backup_file, bool silent=false);
// nuke the service
bool nuke(); // nukes all data for this service on the remote server
bool nuke(bool silent=false); // nukes all data for this service on the remote server
bool fullnuke(); // nuke all data for this service on the remote server, and then nukes all the local service definitionfiles
// launch an interactive ssh session on a server or service

View File

@ -14,6 +14,13 @@ namespace fs = std::filesystem;
namespace dropshell {
bool SIvalid(const LocalServiceInfo& service_info) {
return !service_info.service_name.empty() &&
!service_info.template_name.empty() &&
!service_info.local_service_path.empty() &&
!service_info.local_template_path.empty();
}
std::vector<LocalServiceInfo> get_server_services_info(const std::string& server_name) {
std::vector<LocalServiceInfo> services;
@ -64,7 +71,8 @@ LocalServiceInfo get_service_info(const std::string &server_name, const std::str
// now set the template name and path.
std::map<std::string, std::string> variables;
get_all_service_env_vars(server_name, service_name, variables);
if (!get_all_service_env_vars(server_name, service_name, variables))
return LocalServiceInfo();
// confirm TEMPLATE is defined.
auto it = variables.find("TEMPLATE");
@ -207,10 +215,16 @@ bool create_service(const std::string &server_name, const std::string &template_
void get_all_service_env_vars(const std::string &server_name, const std::string &service_name, std::map<std::string, std::string> & all_env_vars)
bool get_all_service_env_vars(const std::string &server_name, const std::string &service_name, std::map<std::string, std::string> & all_env_vars)
{
all_env_vars.clear();
if (localpath::service(server_name, service_name).empty() || !fs::exists(localpath::service(server_name, service_name)))
{
std::cerr << "Error: Service not found: " << service_name << std::endl;
return false;
}
// add in some handy variables.
all_env_vars["CONFIG_PATH"] = remotepath::service_config(server_name,service_name);
all_env_vars["SERVER"] = server_name;
@ -247,13 +261,22 @@ void get_all_service_env_vars(const std::string &server_name, const std::string
std::cerr << "The TEMPLATE variable is required to determine the template name." << std::endl;
std::cerr << "Please check the service.env file and the .template_info.env file in:" << std::endl;
std::cerr << " " << localpath::service(server_name, service_name) << std::endl << std::endl;
return;
return false;
}
template_info tinfo = gTemplateManager().get_template_info(it->second);
if (tinfo.is_set())
load_env_file(tinfo.local_template_path()/"_default.env");
else
if (!tinfo.is_set()) {
std::cerr << "Error: Template '" << it->second << "' not found" << std::endl;
return false;
}
std::string default_env_file = tinfo.local_template_path()/"_default.env";
if (!fs::exists(default_env_file)) {
std::cerr << "Error: Template default env file '" << default_env_file << "' not found" << std::endl;
return false;
}
load_env_file(default_env_file);
return true;
}
} // namespace dropshell

View File

@ -15,13 +15,15 @@ namespace dropshell {
std::string local_template_path;
};
bool SIvalid(const LocalServiceInfo& service_info);
std::vector<LocalServiceInfo> get_server_services_info(const std::string& server_name);
LocalServiceInfo get_service_info(const std::string& server_name, const std::string& service_name);
std::set<std::string> get_used_commands(const std::string& server_name, const std::string& service_name);
// get all env vars for a given service
void get_all_service_env_vars(const std::string& server_name, const std::string& service_name, std::map<std::string, std::string> & all_env_vars);
bool get_all_service_env_vars(const std::string& server_name, const std::string& service_name, std::map<std::string, std::string> & all_env_vars);
// list all backups for a given service (across all servers)
std::set<std::string> list_backups(const std::string& server_name, const std::string& service_name);