This commit is contained in:
j
2025-12-30 09:31:21 +13:00
parent 0917e1e3f3
commit 4bcbf12088
6 changed files with 79 additions and 59 deletions

View File

@@ -75,6 +75,7 @@ required_files=(
"$AGENT_PATH/bb64" "$AGENT_PATH/bb64"
"$AGENT_PATH/common.sh" "$AGENT_PATH/common.sh"
"$AGENT_PATH/datacommands.sh" "$AGENT_PATH/datacommands.sh"
"$AGENT_PATH/ds_run.sh"
) )
# check if all files exist # check if all files exist

View File

@@ -3,21 +3,28 @@ set -euo pipefail
# Dropshell Run - Execute a service command on the remote server # Dropshell Run - Execute a service command on the remote server
# #
# Usage: ds_run.sh SERVER SERVICE COMMAND [args...] # Usage: ds_run.sh SERVICE COMMAND [args...]
# #
# Remote directory structure: # Remote directory structure:
# DROPSHELL_DIR/ # // |-- server_info.env
# ├── agent/ # // |-- server.json
# │ ├── ds_run.sh (this script) # // |-- backups
# │ └── common.sh # // |-- temp_files
# └── services/<service>/ # // |-- agent
# ├── config/ # // | |-- bb64
# │ └── service.env # // | |-- ds_run.sh (this script)
# └── template/ # // | |-- common.sh
# ├── template_info.env # // | |-- (other agent files)
# ├── install.sh, uninstall.sh, etc. # // |-- services
# └── config/ # // |-- service name
# └── service.env (template defaults) # // |-- config
# // |-- service.env (actual service config)
# // |-- template
# // |-- (script files)
# // |-- template_info.env
# // |-- config
# // |-- service.env (default service config)
# // |-- (other template/example config files)
# -- Determine paths -- # -- Determine paths --
SCRIPT_PATH="$(readlink -f "${BASH_SOURCE[0]}")" SCRIPT_PATH="$(readlink -f "${BASH_SOURCE[0]}")"
@@ -37,10 +44,9 @@ if [[ $# -lt 3 ]]; then
exit 1 exit 1
fi fi
export SERVER="$1" export SERVICE="$1"
export SERVICE="$2" export DSCOMMAND="$2"
export DSCOMMAND="$3" shift 2
shift 3
# Suppress Docker CLI hints # Suppress Docker CLI hints
export DOCKER_CLI_HINTS=false export DOCKER_CLI_HINTS=false
@@ -50,6 +56,7 @@ export CONFIG_PATH="${DROPSHELL_DIR}/services/${SERVICE}/config"
export TEMPLATE_PATH="${DROPSHELL_DIR}/services/${SERVICE}/template" export TEMPLATE_PATH="${DROPSHELL_DIR}/services/${SERVICE}/template"
# -- Validate service exists -- # -- Validate service exists --
[[ -f "${DROPSHELL_DIR}/server_info.env" ]] || _die "Missing ${DROPSHELL_DIR}/server_info.env"
[[ -d "${CONFIG_PATH}" ]] || _die "Service '${SERVICE}' does not exist on server (missing ${CONFIG_PATH})" [[ -d "${CONFIG_PATH}" ]] || _die "Service '${SERVICE}' does not exist on server (missing ${CONFIG_PATH})"
# -- Load template info (template defaults, loaded first) -- # -- Load template info (template defaults, loaded first) --
@@ -65,6 +72,7 @@ export SERVICE_ENV="${CONFIG_PATH}/service.env"
# -- Source env files with auto-export (set -a exports all assigned variables) -- # -- Source env files with auto-export (set -a exports all assigned variables) --
set -a set -a
source "${DROPSHELL_DIR}/server_info.env"
source "${TEMPLATE_INFO_ENV}" source "${TEMPLATE_INFO_ENV}"
source "${SERVICE_ENV}" source "${SERVICE_ENV}"
set +a set +a

View File

@@ -529,6 +529,17 @@ complete -F _dropshell_completions ds
server, false, user.user); server, false, user.user);
info << "done." << std::endl; info << "done." << std::endl;
// create server_info.env
info << "Creating server_info.env on remote server... " <<std::flush;
std::string rsiep = remotefile(server.get_server_name(),user.user).server_info_env();
sCommand cmd("","echo 'SERVER=\""+server.get_server_name()+"\"' > "+rsiep,{});
if (! execute_ssh_command(server.get_SSH_INFO(user.user),cmd,cMode::Defaults | cMode::NoBB64, nullptr))
{
error << std::endl << "Failed to create " << rsiep << " on " << server.get_server_name() << std::endl;
return 1;
}
info << "done." << std::endl;
// run the agent installer. Can't use BB64 yet, as we're installing it on the remote server. // run the agent installer. Can't use BB64 yet, as we're installing it on the remote server.
bool okay = execute_ssh_command(server.get_SSH_INFO(user.user), sCommand(agent_path, "agent-install.sh",{}), cMode::Defaults | cMode::NoBB64, nullptr); bool okay = execute_ssh_command(server.get_SSH_INFO(user.user), sCommand(agent_path, "agent-install.sh",{}), cMode::Defaults | cMode::NoBB64, nullptr);
if (!okay) if (!okay)
@@ -537,7 +548,6 @@ complete -F _dropshell_completions ds
return 1; return 1;
} }
info << "Installation on " << server.get_server_name() << " complete." << std::endl; info << "Installation on " << server.get_server_name() << " complete." << std::endl;
} }
return 0; return 0;

View File

@@ -170,6 +170,11 @@ namespace dropshell
return remotepath(mServer_name, mUser).DROPSHELL_DIR() + "/" + filenames::server_json; return remotepath(mServer_name, mUser).DROPSHELL_DIR() + "/" + filenames::server_json;
} }
std::string remotefile::server_info_env()
{
return remotepath(mServer_name, mUser).DROPSHELL_DIR() + "/" + filenames::server_info_env;
}
remotepath::remotepath(const std::string &server_name, const std::string &user) : mServer_name(server_name), mUser(user) {} remotepath::remotepath(const std::string &server_name, const std::string &user) : mServer_name(server_name), mUser(user) {}
std::string remotepath::DROPSHELL_DIR() const std::string remotepath::DROPSHELL_DIR() const

View File

@@ -42,6 +42,7 @@ namespace dropshell {
// |-- (...other config files for specific server&service...) // |-- (...other config files for specific server&service...)
namespace filenames { namespace filenames {
static const std::string server_info_env = "server_info.env";
static const std::string template_info_env = "template_info.env"; static const std::string template_info_env = "template_info.env";
static const std::string service_env = "service.env"; static const std::string service_env = "service.env";
static const std::string readme = "README.txt"; static const std::string readme = "README.txt";
@@ -80,6 +81,7 @@ namespace dropshell {
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------
// remote paths // remote paths
// DROPSHELL_DIR // DROPSHELL_DIR
// |-- server_info.env
// |-- server.json // |-- server.json
// |-- backups // |-- backups
// |-- temp_files // |-- temp_files
@@ -102,6 +104,7 @@ namespace dropshell {
remotefile(const std::string &server_name, const std::string &user); remotefile(const std::string &server_name, const std::string &user);
std::string service_env(const std::string &service_name) const; std::string service_env(const std::string &service_name) const;
std::string server_json(); std::string server_json();
std::string server_info_env();
private: private:
std::string mServer_name; std::string mServer_name;
std::string mUser; std::string mUser;

View File

@@ -235,52 +235,45 @@ namespace dropshell
return ""; return "";
// need to construct to change directory and set environment variables // need to construct to change directory and set environment variables
std::string cmdstr;
if (!bb64path.empty()) if (bb64path.empty())
{
if (!mDir.empty())
cmdstr += "cd " + quote(mDir) + " && ";
if (!mVars.empty())
{
// Export variables so they're available for expansion in the command
for (const auto &env_var : mVars)
{
// Basic sanity check - skip invalid variable names
if (!is_valid_env_var_name(env_var.first))
{
error << "Skipping invalid environment variable name: " << env_var.first << std::endl;
continue;
}
// Very basic check for completely broken values that could break the command
// We still use quote() for proper escaping, but warn about suspicious values
const std::string &value = env_var.second;
if (value.find('\0') != std::string::npos)
{
error << "Skipping environment variable with null byte: " << env_var.first << std::endl;
continue;
}
cmdstr += "export " + env_var.first + "=" + quote(dequote(trim(value))) + " && ";
}
}
cmdstr += mCmd;
cmdstr = makesafecmd(bb64path, cmdstr);
}
else
{ // raw! bootstrapping only. { // raw! bootstrapping only.
ASSERT(mVars.empty(), "Bootstrapping command must not have environment variables"); ASSERT(mVars.empty(), "Bootstrapping command must not have environment variables");
if (!mDir.empty()) return (mDir.empty() ? mCmd : mDir + "/" + mCmd);
cmdstr += mDir + "/" + mCmd;
else
cmdstr += mCmd;
} }
return cmdstr; std::string cmdstr;
if (!mDir.empty())
cmdstr += "cd " + quote(mDir) + " && ";
if (!mVars.empty())
{
// Export variables so they're available for expansion in the command
for (const auto &env_var : mVars)
{
// Basic sanity check - skip invalid variable names
if (!is_valid_env_var_name(env_var.first))
{
error << "Skipping invalid environment variable name: " << env_var.first << std::endl;
continue;
}
// Very basic check for completely broken values that could break the command
// We still use quote() for proper escaping, but warn about suspicious values
const std::string &value = env_var.second;
if (value.find('\0') != std::string::npos)
{
error << "Skipping environment variable with null byte: " << env_var.first << std::endl;
continue;
}
cmdstr += "export " + env_var.first + "=" + quote(dequote(trim(value))) + " && ";
}
}
cmdstr += mCmd;
return makesafecmd(bb64path, cmdstr);
} }
bool sSSHInfo::valid() const bool sSSHInfo::valid() const