From d946c18d7cb79d2a6bf9eb6c2c20076491e87ad1 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 12 May 2025 23:08:56 +1200 Subject: [PATCH] move to bb64 --- remote_host_autosetup/host_autosetup.sh | 8 ----- src/commands/install.cpp | 4 +-- src/config.cpp | 8 +++++ src/config.hpp | 2 +- src/main.cpp | 1 - src/server_env_manager.cpp | 48 ++++++++++++++----------- src/server_env_manager.hpp | 4 +-- src/service_runner.cpp | 8 ++--- src/services.cpp | 1 + src/utils/directories.cpp | 6 ++++ src/utils/directories.hpp | 4 +++ src/utils/execute.cpp | 31 ++++++++++------ src/utils/execute.hpp | 25 +++++++------ templates/dropshell-agent/install.sh | 31 ++++++++++++++++ 14 files changed, 120 insertions(+), 61 deletions(-) diff --git a/remote_host_autosetup/host_autosetup.sh b/remote_host_autosetup/host_autosetup.sh index d76fc4a..3187005 100755 --- a/remote_host_autosetup/host_autosetup.sh +++ b/remote_host_autosetup/host_autosetup.sh @@ -102,14 +102,6 @@ if [ "$ARCH" != "aarch64" ] && [ "$ARCH" != "x86_64" ]; then fi -#----------------------------------------- -# install bb64 -curl -fsSL https://gitea.jde.nz/j/bb64/raw/branch/main/install.sh -o ./install-bb64.sh && bash ./install-bb64.sh && rm ./install-bb64.sh - -#----------------------------------------- - - - echo "Installation complete." #-------------------------------- diff --git a/src/commands/install.cpp b/src/commands/install.cpp index 16db0be..7fd0c71 100644 --- a/src/commands/install.cpp +++ b/src/commands/install.cpp @@ -88,7 +88,7 @@ bool install_service(const std::string& server, const std::string& service, bool // Create service directory std::string remote_service_path = remotepath::service(server, service); std::string mkdir_cmd = "mkdir -p " + quote(remote_service_path); - if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand(mkdir_cmd), cMode::Silent)) + if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("",remotepath::executables(server), mkdir_cmd, {}), cMode::Silent)) { std::cerr << "Failed to create service directory " << remote_service_path << std::endl; return false; @@ -96,7 +96,7 @@ bool install_service(const std::string& server, const std::string& service, bool // Check if rsync is installed on remote host std::string check_rsync_cmd = "which rsync"; - if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand(check_rsync_cmd), cMode::Silent)) + if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("",remotepath::executables(server), check_rsync_cmd, {}), cMode::Silent)) { std::cerr << "rsync is not installed on the remote host" << std::endl; return false; diff --git a/src/config.cpp b/src/config.cpp index dd3ab0a..627b297 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -61,6 +61,8 @@ bool config::save_config(bool create_aux_directories) std::string dropshell_base = homedir + "/.dropshell"; mConfig["tempfiles"] = dropshell_base + "/tmp"; mConfig["backups"] = dropshell_base + "/backups"; + mConfig["executables"] = dropshell_base + "/executables"; + mConfig["template_cache"] = dropshell_base + "/template_cache"; mConfig["template_registry_URLs"] = { "https://templates.dropshell.app" @@ -68,6 +70,7 @@ bool config::save_config(bool create_aux_directories) mConfig["template_local_paths"] = { dropshell_base + "/local_templates" }; + mConfig["server_definition_paths"] = { dropshell_base + "/servers" }; @@ -116,6 +119,11 @@ std::string config::get_local_template_cache_path() { return mConfig["template_cache"]; } +std::string config::get_local_executables_path() +{ + return mConfig["executables"]; +} + std::vector config::get_template_registry_urls() { nlohmann::json template_registry_urls = mConfig["template_registry_URLs"]; std::vector urls; diff --git a/src/config.hpp b/src/config.hpp index aa70fe1..fe15672 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -20,7 +20,7 @@ class config { std::string get_local_tempfiles_path(); std::string get_local_backup_path(); std::string get_local_template_cache_path(); - + std::string get_local_executables_path(); std::vector get_template_registry_urls(); std::vector get_template_local_paths(); std::vector get_local_server_definition_paths(); diff --git a/src/main.cpp b/src/main.cpp index d29ff02..3f23907 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -145,7 +145,6 @@ auto command_match = [](const std::string& cmd_list, int argc, char* argv[]) -> int old_main(int argc, char* argv[]) { HAPPYEXIT("hash", hash_demo_raw(safearg(argc,argv,2))) - HAPPYEXIT("makesafecmd", std::cout<second; } - -sCommand server_env_manager::construct_standard_template_run_cmd(const std::string &service_name, const std::string &command, std::vector args, bool silent) const +std::optional server_env_manager::construct_standard_template_run_cmd(const std::string &service_name, const std::string &command, const std::vector args, const bool silent) const { if (command.empty()) - return sCommand(); + return std::nullopt; std::string remote_service_template_path = remotepath::service_template(mServerName,service_name); std::string script_path = remote_service_template_path + "/" + command + ".sh"; @@ -113,7 +112,7 @@ sCommand server_env_manager::construct_standard_template_run_cmd(const std::stri std::map 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(); + return std::nullopt; } std::string argstr = ""; @@ -121,23 +120,29 @@ sCommand server_env_manager::construct_standard_template_run_cmd(const std::stri argstr += " " + quote(dequote(trim(arg))); } - sCommand scommand(remote_service_template_path, quote(script_path) + argstr + (silent ? " > /dev/null 2>&1" : ""), env_vars); + sCommand sc( + remote_service_template_path, + remotepath::executables(mServerName), + quote(script_path) + argstr + (silent ? " > /dev/null 2>&1" : ""), + env_vars + ); - if (scommand.empty()) + if (sc.empty()) { std::cerr << "Error: Failed to construct command for " << service_name << " " << command << std::endl; - - return scommand; + return std::nullopt; + } + return sc; } bool server_env_manager::check_remote_dir_exists(const std::string &dir_path) const { - sCommand scommand("test -d " + quote(dir_path)); + sCommand scommand("",remotepath::executables(mServerName),"test -d " + quote(dir_path),{}); return execute_ssh_command(get_SSH_INFO(), scommand, cMode::Silent); } bool server_env_manager::check_remote_file_exists(const std::string& file_path) const { - sCommand scommand("test -f " + quote(file_path)); + sCommand scommand("",remotepath::executables(mServerName),"test -f " + quote(file_path),{}); return execute_ssh_command(get_SSH_INFO(), scommand, cMode::Silent); } @@ -151,7 +156,7 @@ bool server_env_manager::check_remote_items_exist(const std::vector file_names_str += std::filesystem::path(file_path).filename().string() + " "; } // check if all items in the vector exist on the remote server, in a single command. - sCommand scommand("for item in " + file_paths_str + "; do test -f $item; done"); + sCommand scommand("",remotepath::executables(mServerName),"for item in " + file_paths_str + "; do test -f $item; done",{}); bool okay = execute_ssh_command(get_SSH_INFO(), scommand, cMode::Silent); if (!okay) { @@ -182,7 +187,7 @@ bool server_env_manager::remove_remote_dir(const std::string &dir_path, bool sil if (!silent) std::cout << "Running command: " << remote_cmd << std::endl; - sCommand scommand(remote_cmd); + sCommand scommand("",remotepath::executables(mServerName),remote_cmd,{}); cMode mode = (silent ? cMode::Silent : cMode::None); return execute_ssh_command(get_SSH_INFO(), scommand, mode); @@ -190,33 +195,36 @@ bool server_env_manager::remove_remote_dir(const std::string &dir_path, bool sil bool server_env_manager::run_remote_template_command(const std::string &service_name, const std::string &command, std::vector args, bool silent, std::map extra_env_vars) const { - sCommand scommand = construct_standard_template_run_cmd(service_name, command, args, silent); + auto scommand = construct_standard_template_run_cmd(service_name, command, args, silent); + if (!scommand.has_value()) + return false; // add the extra env vars to the command for (const auto& [key, value] : extra_env_vars) - scommand.add_env_var(key, value); + scommand->add_env_var(key, value); - if (scommand.get_command_to_run().empty()) + if (scommand->get_command_to_run().empty()) return false; cMode mode = (command=="ssh") ? (cMode::Interactive) : cMode::Silent; - return execute_ssh_command(get_SSH_INFO(), scommand, mode); + return execute_ssh_command(get_SSH_INFO(), scommand.value(), mode); } 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, std::map extra_env_vars) const { - sCommand scommand = construct_standard_template_run_cmd(service_name, command, args, false); - if (scommand.get_command_to_run().empty()) + auto scommand = construct_standard_template_run_cmd(service_name, command, args, false); + if (!scommand.has_value()) return false; // add the extra env vars to the command for (const auto& [key, value] : extra_env_vars) - scommand.add_env_var(key, value); + scommand->add_env_var(key, value); cMode mode = cMode::CaptureOutput; - return execute_ssh_command(get_SSH_INFO(), scommand, mode, &output); + return execute_ssh_command(get_SSH_INFO(), scommand.value(), mode, &output); } + // base64 <<< "FOO=BAR WHEE=YAY bash ./test.sh" // echo YmFzaCAtYyAnRk9PPUJBUiBXSEVFPVlBWSBiYXNoIC4vdGVzdC5zaCcK | base64 -d | bash diff --git a/src/server_env_manager.hpp b/src/server_env_manager.hpp index 63f888a..b1e9223 100644 --- a/src/server_env_manager.hpp +++ b/src/server_env_manager.hpp @@ -10,7 +10,7 @@ #include #include #include "utils/execute.hpp" - +#include namespace dropshell { class server_env_manager; @@ -61,7 +61,7 @@ class server_env_manager { std::vector args, std::string & output, bool silent, std::map extra_env_vars) const; private: - sCommand construct_standard_template_run_cmd(const std::string& service_name, const std::string& command, std::vector args, bool silent) const; + std::optional construct_standard_template_run_cmd(const std::string& service_name, const std::string& command, const std::vector args, const bool silent) const; private: std::string mServerName; diff --git a/src/service_runner.cpp b/src/service_runner.cpp index b879293..00d1d92 100644 --- a/src/service_runner.cpp +++ b/src/service_runner.cpp @@ -236,12 +236,12 @@ bool service_runner::interactive_ssh(const std::string & server_name, const std: return false; } - sCommand scommand("bash"); server_env_manager env(server_name); if (!env.is_valid()) { std::cerr << "Error: Invalid server environment file: " << server_name << std::endl; return false; } + sCommand scommand("",remotepath::executables(server_name), "bash",{}); return execute_ssh_command(env.get_SSH_INFO(), scommand, cMode::Interactive); } @@ -426,7 +426,7 @@ bool service_runner::backup(bool silent) { std::string remote_backups_dir = remotepath::backups(mServer); if (!silent) std::cout << "Remote backups directory on "<< mServer <<": " << remote_backups_dir << std::endl; std::string mkdir_cmd = "mkdir -p " + quote(remote_backups_dir); - if (!execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand(mkdir_cmd), cMode::Silent)) { + if (!execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand("",remotepath::executables(mServer), mkdir_cmd, {}), cMode::Silent)) { std::cerr << "Failed to create backups directory on server" << std::endl; return false; } @@ -484,7 +484,7 @@ cRemoteTempFolder::cRemoteTempFolder(const server_env_manager &server_env) : mSe { std::string p = remotepath::temp_files(server_env.get_server_name()) + "/" + random_alphanumeric_string(10); std::string mkdir_cmd = "mkdir -p " + quote(p); - if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand(mkdir_cmd), cMode::Silent)) + if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("",remotepath::executables(server_env.get_server_name()), mkdir_cmd, {}), cMode::Silent)) std::cerr << "Failed to create temp directory on server" << std::endl; else mPath = p; @@ -493,7 +493,7 @@ cRemoteTempFolder::cRemoteTempFolder(const server_env_manager &server_env) : mSe cRemoteTempFolder::~cRemoteTempFolder() { std::string rm_cmd = "rm -rf " + quote(mPath); - execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand(rm_cmd), cMode::Silent); + execute_ssh_command(mServerEnv.get_SSH_INFO(), sCommand("",remotepath::executables(mServerEnv.get_server_name()), rm_cmd, {}), cMode::Silent); } std::string cRemoteTempFolder::path() const diff --git a/src/services.cpp b/src/services.cpp index 3285c1f..540d8c9 100644 --- a/src/services.cpp +++ b/src/services.cpp @@ -230,6 +230,7 @@ bool get_all_service_env_vars(const std::string &server_name, const std::string all_env_vars["SERVER"] = server_name; all_env_vars["SERVICE"] = service_name; all_env_vars["AGENT_PATH"] = remotepath::service_template(server_name, "dropshell-agent") + "/shared"; + all_env_vars["EXECUTABLES"] = remotepath::executables(server_name); ServerInfo server_info = get_server_info(server_name); if (server_info.ssh_host.empty()) diff --git a/src/utils/directories.cpp b/src/utils/directories.cpp index 3e43780..ceff6cf 100644 --- a/src/utils/directories.cpp +++ b/src/utils/directories.cpp @@ -142,6 +142,12 @@ namespace remotepath { return (dsp.empty() ? "" : (dsp + "/temp_files")); } + std::string executables(const std::string &server_name) + { + std::string dsp = DROPSHELL_DIR(server_name); + return (dsp.empty() ? "" : (dsp + "/executables")); + } + std::string service_env(const std::string &server_name, const std::string &service_name) { std::string service_path = service_config(server_name, service_name); diff --git a/src/utils/directories.hpp b/src/utils/directories.hpp index 860f52c..a1a7036 100644 --- a/src/utils/directories.hpp +++ b/src/utils/directories.hpp @@ -27,6 +27,8 @@ namespace dropshell { // temp files path + // executables path + // template cache path // |-- templates // | |-- .json @@ -64,6 +66,7 @@ namespace dropshell { // DROPSHELL_DIR // |-- backups // |-- temp_files + // |-- executables // |-- services // |-- service name // |-- config @@ -86,6 +89,7 @@ namespace dropshell { std::string service_template(const std::string &server_name, const std::string &service_name); std::string backups(const std::string &server_name); std::string temp_files(const std::string &server_name); + std::string executables(const std::string &server_name); } // namespace remotepath //------------------------------------------------------------------------------------------------ diff --git a/src/utils/execute.cpp b/src/utils/execute.cpp index 52311ec..17e71a3 100644 --- a/src/utils/execute.cpp +++ b/src/utils/execute.cpp @@ -11,6 +11,7 @@ #include "execute.hpp" #include "utils/utils.hpp" #include "utils/b64ed.hpp" +#include "config.hpp" bool EXITSTATUSCHECK(int ret) { @@ -69,8 +70,15 @@ namespace dropshell return EXITSTATUSCHECK(ret); } - bool execute_local_command(const sCommand &command, std::string *output /* = nullptr */, cMode mode /* = cMode::None */) + bool execute_local_command(std::string command, std::string *output, cMode mode) { + return execute_local_command("",command,{}, output, mode); + } + + bool execute_local_command(std::string directory_to_run_in, std::string command_to_run, const std::map &env_vars, std::string *output, cMode mode) + { + sCommand command(directory_to_run_in, gConfig().get_local_executables_path(), command_to_run, env_vars); + if (hasFlag(mode, cMode::Interactive)) { ASSERT(!hasFlag(mode, cMode::CaptureOutput), "Interactive mode and capture output mode cannot be used together"); @@ -102,9 +110,9 @@ namespace dropshell return ok; } - bool execute_ssh_command(const sSSHInfo &ssh_info, const sCommand &command, cMode mode, std::string *output) + bool execute_ssh_command(const sSSHInfo &ssh_info, const sCommand &remote_command, cMode mode, std::string *output) { - if (command.get_command_to_run().empty()) + if (remote_command.get_command_to_run().empty()) return false; ASSERT(!(hasFlag(mode, cMode::CaptureOutput) && output == nullptr), "Capture output mode must be used with an output string"); @@ -113,29 +121,32 @@ namespace dropshell ssh_cmd << "ssh -p " << ssh_info.port << " " << (hasFlag(mode, cMode::Interactive) ? "-tt " : "") << ssh_info.user << "@" << ssh_info.host; - std::string cmdstr = command.construct_cmd(); - sCommand ssh_command(ssh_cmd.str() + " " + cmdstr); - - bool rval = execute_local_command(ssh_command, output, mode); + bool rval = execute_local_command( + "", // directory to run in + ssh_cmd.str() + " " + remote_command.construct_cmd(), // local command to run + {}, // environment variables + output, // output string + mode // mode + ); if (!rval && !hasFlag(mode, cMode::Silent)) { std::cerr << std::endl << std::endl; std::cerr << "Error: Failed to execute ssh command:" << std::endl; - std::cerr << "\033[90m" << ssh_command.get_command_to_run() << "\033[0m" << std::endl; + std::cerr << "\033[90m" << ssh_cmd.str() + " " + remote_command.construct_cmd() << "\033[0m" << std::endl; std::cerr << std::endl << std::endl; } return rval; } - std::string makesafecmd(const std::string &command) + std::string sCommand::makesafecmd(const std::string &command) const { if (command.empty()) return ""; std::string encoded = base64_encode(dequote(trim(command))); - std::string commandstr = "bb64 " + encoded; + std::string commandstr = mExecutablesPath + "/bb64 " + encoded; return commandstr; } diff --git a/src/utils/execute.hpp b/src/utils/execute.hpp index b50bc57..2d2c3ee 100644 --- a/src/utils/execute.hpp +++ b/src/utils/execute.hpp @@ -30,42 +30,41 @@ typedef struct sSSHInfo { std::string port; } sSSHInfo; -bool execute_local_command(const sCommand & command, std::string * output = nullptr, cMode mode = cMode::None); -bool execute_ssh_command(const sSSHInfo & ssh_info, const sCommand & command, cMode mode = cMode::None, std::string * output = nullptr); - -std::string makesafecmd(const std::string& command); +bool execute_local_command(std::string command, std::string * output = nullptr, cMode mode = cMode::None); +bool execute_local_command(std::string directory_to_run_in, std::string command_to_run, const std::map & env_vars, std::string * output = nullptr, cMode mode = cMode::None); +bool execute_ssh_command(const sSSHInfo & ssh_info, const sCommand & remote_command, cMode mode = cMode::None, std::string * output = nullptr); // ------------------------------------------------------------------------------------------------ - // class to hold a command to run on the remote server. class sCommand { public: - sCommand(std::string directory_to_run_in, std::string command_to_run, const std::map & env_vars) : - 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({}) {} + sCommand(std::string directory_to_run_in, std::string executables_path, std::string command_to_run, const std::map & env_vars) : + mDir(directory_to_run_in), mExecutablesPath(executables_path), mCmd(command_to_run), mVars(env_vars) {} std::string get_directory_to_run_in() const { return mDir; } + std::string get_executables_path() const { return mExecutablesPath; } std::string get_command_to_run() const { return mCmd; } const std::map& get_env_vars() const { return mVars; } void add_env_var(const std::string& key, const std::string& value) { mVars[key] = value; } bool empty() const { return mCmd.empty(); } - + std::string construct_cmd() const; - + + private: + std::string makesafecmd(const std::string& command) const; + private: std::string mDir; + std::string mExecutablesPath; std::string mCmd; std::map mVars; }; - } // namespace dropshell diff --git a/templates/dropshell-agent/install.sh b/templates/dropshell-agent/install.sh index c6be2d3..43b9e41 100755 --- a/templates/dropshell-agent/install.sh +++ b/templates/dropshell-agent/install.sh @@ -24,6 +24,37 @@ check_prerequisites() { done } + +install_bb64() { + # install bb64 into EXECUTABLES + _check_required_env_vars EXECUTABLES + + ARCH=$(uname -m) + if [[ "$ARCH" == "x86_64" ]]; then + BIN=bb64.amd64 + elif [[ "$ARCH" == "aarch64" || "$ARCH" == "arm64" ]]; then + BIN=bb64.arm64 + else + echo "Unsupported architecture: $ARCH" >&2 + exit 1 + fi + + # create the executables directory if it doesn't exist + mkdir -p ${EXECUTABLES} + + # download bb64 + if ! curl -fsSL https://gitea.jde.nz/public/bb64/releases/download/latest/bb64.${ARCH} -o ${EXECUTABLES}/bb64; then + echo "Failed to download bb64 for architecture: $ARCH" >&2 + exit 1 + fi + chmod +x ${EXECUTABLES}/bb64 +} + + check_prerequisites + +# install bb64 +install_bb64 + exit 0