diff --git a/src/main.cpp b/src/main.cpp index 9281984..49f2a87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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 additional_args; - for (int i=4; i additional_args; + for (int i=4; i 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 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 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 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; diff --git a/src/server_env_manager.hpp b/src/server_env_manager.hpp index e4f4bf8..d25d58d 100644 --- a/src/server_env_manager.hpp +++ b/src/server_env_manager.hpp @@ -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; diff --git a/src/service_runner.cpp b/src/service_runner.cpp index 4a8d0f7..08a802e 100644 --- a/src/service_runner.cpp +++ b/src/service_runner.cpp @@ -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; diff --git a/src/service_runner.hpp b/src/service_runner.hpp index 412253f..88b66d7 100644 --- a/src/service_runner.hpp +++ b/src/service_runner.hpp @@ -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 diff --git a/src/services.cpp b/src/services.cpp index 52d72ad..3285c1f 100644 --- a/src/services.cpp +++ b/src/services.cpp @@ -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 get_server_services_info(const std::string& server_name) { std::vector 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 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 & all_env_vars) +bool get_all_service_env_vars(const std::string &server_name, const std::string &service_name, std::map & 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 diff --git a/src/services.hpp b/src/services.hpp index c6b8bb6..447cc12 100644 --- a/src/services.hpp +++ b/src/services.hpp @@ -15,13 +15,15 @@ namespace dropshell { std::string local_template_path; }; + bool SIvalid(const LocalServiceInfo& service_info); + std::vector 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 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 & all_env_vars); + bool get_all_service_env_vars(const std::string& server_name, const std::string& service_name, std::map & all_env_vars); // list all backups for a given service (across all servers) std::set list_backups(const std::string& server_name, const std::string& service_name);