move to bb64
Some checks failed
Dropshell Test / Build_and_Test (push) Has been cancelled

This commit is contained in:
Your Name 2025-05-12 23:08:56 +12:00
parent 8fc3384c03
commit d946c18d7c
14 changed files with 120 additions and 61 deletions

View File

@ -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."
#--------------------------------

View File

@ -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;

View File

@ -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<std::string> config::get_template_registry_urls() {
nlohmann::json template_registry_urls = mConfig["template_registry_URLs"];
std::vector<std::string> urls;

View File

@ -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<std::string> get_template_registry_urls();
std::vector<std::string> get_template_local_paths();
std::vector<std::string> get_local_server_definition_paths();

View File

@ -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<<makesafecmd(safearg(argc,argv,2))<<std::endl)
HAPPYEXIT("version", printversion())
BOOLEXIT("test-template", gTemplateManager().test_template(safearg(argc,argv,2)))
ASSERT(safearg(argc,argv,1) != "assert", "Hello! Here is an assert.");

View File

@ -101,11 +101,10 @@ std::string server_env_manager::get_variable(const std::string& name) const {
}
return it->second;
}
sCommand server_env_manager::construct_standard_template_run_cmd(const std::string &service_name, const std::string &command, std::vector<std::string> args, bool silent) const
std::optional<sCommand> server_env_manager::construct_standard_template_run_cmd(const std::string &service_name, const std::string &command, const std::vector<std::string> 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<std::string, std::string> 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<std::string>
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<std::string> args, bool silent, std::map<std::string, std::string> 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<std::string> args, std::string &output, bool silent, std::map<std::string, std::string> 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

View File

@ -10,7 +10,7 @@
#include <memory>
#include <vector>
#include "utils/execute.hpp"
#include <optional>
namespace dropshell {
class server_env_manager;
@ -61,7 +61,7 @@ class server_env_manager {
std::vector<std::string> args, std::string & output, bool silent, std::map<std::string, std::string> extra_env_vars) const;
private:
sCommand construct_standard_template_run_cmd(const std::string& service_name, const std::string& command, std::vector<std::string> args, bool silent) const;
std::optional<sCommand> construct_standard_template_run_cmd(const std::string& service_name, const std::string& command, const std::vector<std::string> args, const bool silent) const;
private:
std::string mServerName;

View File

@ -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

View File

@ -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())

View File

@ -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);

View File

@ -27,6 +27,8 @@ namespace dropshell {
// temp files path
// executables path
// template cache path
// |-- templates
// | |-- <template_name>.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
//------------------------------------------------------------------------------------------------

View File

@ -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<std::string, std::string> &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;
}

View File

@ -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<std::string, std::string> & 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<std::string, std::string> & 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<std::string, std::string> & 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<std::string, std::string>& 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<std::string, std::string> mVars;
};
} // namespace dropshell

View File

@ -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