dropshell release 2025.0524.1149
Some checks failed
Dropshell Test / Build_and_Test (push) Failing after 17s

This commit is contained in:
Your Name 2025-05-24 11:49:24 +12:00
parent 0934179053
commit 763293c7d0
10 changed files with 64 additions and 60 deletions

View File

@ -1,5 +1,5 @@
SSH_ADDRESS=localhost SSH_ADDRESS=localhost
SSH_PORT=22 SSH_PORT=22
SSH_USER=$(whoami) SSH_UNPRIVILEGED_USER=$(whoami)

View File

@ -152,7 +152,7 @@ namespace dropshell
recursive_copy(tinfo.local_template_path() / "config", service_dir); recursive_copy(tinfo.local_template_path() / "config", service_dir);
// append TEMPLATE_HASH to the .template_info.env file // append TEMPLATE_HASH to the .template_info.env file
std::string template_info_env_file = service_dir + "/.template_info.env"; std::string template_info_env_file = service_dir + "/" + filenames::template_info_env;
std::ofstream template_info_env_file_out(template_info_env_file); std::ofstream template_info_env_file_out(template_info_env_file);
template_info_env_file_out << "TEMPLATE_HASH=" << tinfo.hash() << std::endl; template_info_env_file_out << "TEMPLATE_HASH=" << tinfo.hash() << std::endl;
template_info_env_file_out.close(); template_info_env_file_out.close();
@ -191,12 +191,12 @@ namespace dropshell
} }
info << "Setting SSH_USER to " << sshuser << " in service.env file" << std::endl; info << "Setting SSH_USER to " << sshuser << " in the " << filenames::service_env << " file" << std::endl;
{ // edit the service.env file to set the SSH_USER. { // edit the service.env file to set the SSH_USER.
std::string template_service_env_file = tinfo.local_template_path() / "config" / "service.env"; std::string template_service_env_file = tinfo.local_template_path() / "config" / filenames::service_env;
ASSERT(std::filesystem::exists(template_service_env_file), "Template service env file not found: " + template_service_env_file); ASSERT(std::filesystem::exists(template_service_env_file), "Template service env file not found: " + template_service_env_file);
std::ifstream template_service_env_file_in(template_service_env_file); std::ifstream template_service_env_file_in(template_service_env_file);
std::ofstream service_env_file_out(service_dir + "/service.env"); std::ofstream service_env_file_out(localfile::template_info_env(server_name, service_name));
std::string line; std::string line;
while (std::getline(template_service_env_file_in, line)) while (std::getline(template_service_env_file_in, line))
{ {
@ -239,6 +239,23 @@ namespace dropshell
return true; return true;
} }
bool merge_updated_service_template(const std::string &server_name, const std::string &service_name)
{
LocalServiceInfo service_info = get_service_info(server_name, service_name);
ASSERT(SIvalid(service_info), "Service info is not valid for " + service_name + " on " + server_name);
template_info tinfo = gTemplateManager().get_template_info(service_info.template_name);
ASSERT(tinfo.is_set(), "Failed to load template " + service_info.template_name);
// copy across .template_info.env file
std::string template_service_env_file = "";
std::string target_service_env_file = localfile::template_info_env(server_name, service_name);
ASSERT(std::filesystem::exists(template_service_env_file), "Template service env file not found: " + template_service_env_file);
return true;
}
} // namespace shared_commands } // namespace shared_commands
} // namespace dropshell } // namespace dropshell

View File

@ -70,6 +70,15 @@ namespace dropshell
if (!SIvalid(service_info)) if (!SIvalid(service_info))
return false; return false;
if (!service_info.service_template_hash_match)
{
warning << "Service " << service << " is using an old template. Updating. " << std::endl;
if (!merge_updated_service_template(server_env.get_server_name(), service))
{
error << "Failed to merge updated service template. " << std::endl;
return false;
}
}
maketitle("Installing " + service + " (" + service_info.template_name + ") on " + server); maketitle("Installing " + service + " (" + service_info.template_name + ") on " + server);

View File

@ -98,6 +98,7 @@ namespace dropshell
// defined in create-service.cpp // defined in create-service.cpp
bool create_service(const std::string &server_name, const std::string &template_name, const std::string &service_name, std::string user_override=""); bool create_service(const std::string &server_name, const std::string &template_name, const std::string &service_name, std::string user_override="");
bool merge_updated_service_template(const std::string &server_name, const std::string &service_name);
} // namespace shared_commands } // namespace shared_commands
} // namespace dropshell } // namespace dropshell

View File

@ -28,23 +28,22 @@ namespace dropshell
if (server_name.empty()) if (server_name.empty())
return; return;
// Construct the full path to server.json std::string server_json_path = localfile::server_json(server_name);
std::string server_env_path = localfile::server_json(server_name);
// Check if file exists // Check if file exists
if (!std::filesystem::exists(server_env_path)) if (!std::filesystem::exists(server_json_path))
{ {
std::cerr << "Server environment file not found: " + server_env_path << " for server " << server_name << std::endl; std::cerr << "Server environment file not found: " + server_json_path << " for server " << server_name << std::endl;
return; return;
} }
try try
{ {
// Use envmanager to handle the environment file // Use envmanager to handle the environment file
nlohmann::json server_env_json = nlohmann::json::parse(std::ifstream(server_env_path)); nlohmann::json server_env_json = nlohmann::json::parse(std::ifstream(server_json_path));
if (server_env_json.empty()) if (server_env_json.empty())
{ {
error << "Failed to parse server environment file at "<< server_env_path << std::endl; error << "Failed to parse server environment file at "<< server_json_path << std::endl;
info << "The returned json was empty." << std::endl; info << "The returned json was empty." << std::endl;
return; return;
} }
@ -96,7 +95,7 @@ namespace dropshell
if (mUsers.empty()) if (mUsers.empty())
{ {
error << "No users defined in server configuration " << server_env_path << std::endl; error << "No users defined in server configuration " << server_json_path << std::endl;
return; return;
} }
@ -104,7 +103,7 @@ namespace dropshell
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
error << "Failed to parse " << server_env_path << std::endl; error << "Failed to parse " << server_json_path << std::endl;
error << "Error: " << e.what() << std::endl; error << "Error: " << e.what() << std::endl;
mValid = false; mValid = false;
@ -334,30 +333,10 @@ namespace dropshell
argstr += " " + quote(dequote(trim(arg))); argstr += " " + quote(dequote(trim(arg)));
} }
if (env_vars.find("RUNAS") == env_vars.end())
{
error << "Error: RUNAS is not set in .template_info.env for the service." << std::endl;
return std::nullopt;
}
std::string runas = env_vars.find("RUNAS")->second;
if (runas != "root" && runas != "user")
{
error << "Error: RUNAS is not set to root or user in .template_info.env for the service." << std::endl;
return std::nullopt;
}
bool run_as_root = runas == "root";
if (run_as_root && !hasRootUser())
{
error << "Error: The service " << service_name << " is set to run as root on the remote server, but the server environment does not allow root services." << std::endl;
return std::nullopt;
}
sCommand sc( sCommand sc(
remote_service_template_path, remote_service_template_path,
quote(script_path) + argstr + (silent ? " > /dev/null 2>&1" : ""), quote(script_path) + argstr + (silent ? " > /dev/null 2>&1" : ""),
env_vars, env_vars);
run_as_root);
if (sc.empty()) if (sc.empty())
{ {
@ -427,7 +406,7 @@ namespace dropshell
// 3. create a template server.env file in the server directory // 3. create a template server.env file in the server directory
std::string user = getenv("USER"); std::string user = getenv("USER");
std::string server_env_path = server_dir + "/server.json"; std::string server_env_path = server_dir + "/" + filenames::server_json;
std::ofstream server_env_file(server_env_path); std::ofstream server_env_file(server_env_path);
server_env_file << "{" << std::endl; server_env_file << "{" << std::endl;
server_env_file << " \"SSH_HOST\": \"" << server_name << "\"," << std::endl; server_env_file << " \"SSH_HOST\": \"" << server_name << "\"," << std::endl;

View File

@ -67,7 +67,7 @@ namespace dropshell
auto it = variables.find(variable_name); auto it = variables.find(variable_name);
if (it == variables.end()) if (it == variables.end())
{ {
error << "Variable " << variable_name << " not found in the service .template_info.env file" << std::endl; error << "Variable " << variable_name << " not found in the service " << filenames::template_info_env << std::endl;
return false; return false;
} }
return it->second == "true"; return it->second == "true";
@ -237,7 +237,7 @@ namespace dropshell
if (user.empty()) if (user.empty())
{ {
error << "SSH_USER variable not defined in service " << service_name << " on server " << server_name << std::endl; error << "SSH_USER variable not defined in service " << service_name << " on server " << server_name << std::endl;
info << "This variable definition is always required, and usually set int he service.env file." << std::endl; info << "This variable definition is always required, and usually set in the "<<filenames::service_env << " file." << std::endl;
info << "Please check " << localfile::service_env(server_name, service_name) << std::endl; info << "Please check " << localfile::service_env(server_name, service_name) << std::endl;
return false; return false;
} }
@ -256,7 +256,7 @@ namespace dropshell
{ {
error << "TEMPLATE variable not defined in service " << service_name << " on server " << server_name << std::endl; error << "TEMPLATE variable not defined in service " << service_name << " on server " << server_name << std::endl;
info << "The TEMPLATE variable is required to determine the template name." << std::endl; info << "The TEMPLATE variable is required to determine the template name." << std::endl;
info << "Please check the service.env file and the .template_info.env file in:" << std::endl; info << "Please check the " << filenames::service_env << " file and the "<< filenames::template_info_env << " file in:" << std::endl;
info << " " << localpath::service(server_name, service_name) << std::endl info << " " << localpath::service(server_name, service_name) << std::endl
<< std::endl; << std::endl;
return false; return false;

View File

@ -220,9 +220,9 @@
// modify the TEMPLATE=example line in the .template_info.env file to TEMPLATE=<template_name> // modify the TEMPLATE=example line in the .template_info.env file to TEMPLATE=<template_name>
std::string search_string = "TEMPLATE="; std::string search_string = "TEMPLATE=";
std::string replacement_line = "TEMPLATE=" + template_name; std::string replacement_line = "TEMPLATE=" + template_name;
std::string service_env_path = new_template_path + "/config/.template_info.env"; std::string service_env_path = new_template_path + "/config/" + filenames::template_info_env;
if (!replace_line_in_file(service_env_path, search_string, replacement_line)) { if (!replace_line_in_file(service_env_path, search_string, replacement_line)) {
std::cerr << "Error: Failed to replace TEMPLATE= line in the .template_info.env file" << std::endl; std::cerr << "Error: Failed to replace TEMPLATE= line in the " << filenames::template_info_env <<" file" << std::endl;
return false; return false;
} }
@ -306,8 +306,8 @@
std::string template_name = std::filesystem::path(template_path).filename().string(); std::string template_name = std::filesystem::path(template_path).filename().string();
std::vector<std::string> required_files = { std::vector<std::string> required_files = {
"config/service.env", "config/" + filenames::service_env,
"config/.template_info.env", "config/" + filenames::template_info_env,
"install.sh", "install.sh",
"uninstall.sh" "uninstall.sh"
}; };
@ -331,8 +331,8 @@
// check TEMPLATE= line. // check TEMPLATE= line.
std::map<std::string, std::string> all_env_vars; std::map<std::string, std::string> all_env_vars;
std::vector<std::string> env_files = { std::vector<std::string> env_files = {
"config/service.env", "config/" + filenames::service_env,
"config/.template_info.env" "config/" + filenames::template_info_env
}; };
for (const auto& file : env_files) { for (const auto& file : env_files) {
{ // load service.env from the service on this machine. { // load service.env from the service on this machine.

View File

@ -19,7 +19,7 @@ namespace localfile {
// Try ~/.config/dropshell/dropshell.json // Try ~/.config/dropshell/dropshell.json
std::string homedir = localpath::current_user_home(); std::string homedir = localpath::current_user_home();
if (!homedir.empty()) { if (!homedir.empty()) {
fs::path user_path = fs::path(homedir) / ".config" / "dropshell" / "dropshell.json"; fs::path user_path = fs::path(homedir) / ".config" / "dropshell" / filenames::dropshell_json;
return user_path.string(); return user_path.string();
} }
return std::string(); return std::string();
@ -27,18 +27,18 @@ namespace localfile {
std::string server_json(const std::string &server_name) { std::string server_json(const std::string &server_name) {
std::string serverpath = localpath::server(server_name); std::string serverpath = localpath::server(server_name);
return (serverpath.empty() ? "" : (fs::path(serverpath) / "server.json").string()); return (serverpath.empty() ? "" : (fs::path(serverpath) / filenames::server_json).string());
} }
std::string service_env(const std::string &server_name, const std::string &service_name) { std::string service_env(const std::string &server_name, const std::string &service_name) {
std::string servicepath = localpath::service(server_name, service_name); std::string servicepath = localpath::service(server_name, service_name);
return (servicepath.empty() ? "" : (fs::path(servicepath) / "service.env").string()); return (servicepath.empty() ? "" : (fs::path(servicepath) / filenames::service_env).string());
} }
std::string template_info_env(const std::string &server_name, const std::string &service_name) std::string template_info_env(const std::string &server_name, const std::string &service_name)
{ {
std::string servicepath = localpath::service(server_name, service_name); std::string servicepath = localpath::service(server_name, service_name);
return (servicepath.empty() ? "" : (fs::path(servicepath) / ".template_info.env").string()); return (servicepath.empty() ? "" : (fs::path(servicepath) / filenames::template_info_env).string());
} }
std::string template_example() std::string template_example()
@ -165,7 +165,7 @@ namespace localpath {
std::string remotefile::service_env(const std::string &service_name) const std::string remotefile::service_env(const std::string &service_name) const
{ {
return remotepath(mServer_name,mUser).service_config(service_name) + "/service.env"; return remotepath(mServer_name,mUser).service_config(service_name) + "/" + filenames::service_env;
} }
@ -218,12 +218,6 @@ namespace localpath {
return (dsp.empty() ? "" : (dsp + "/agent")); return (dsp.empty() ? "" : (dsp + "/agent"));
} }
// std::string remotepath::service_env(const std::string &service_name) const
// {
// std::string service_path = service_config(service_name);
// return (service_path.empty() ? "" : (service_path + "/service.env"));
// }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
// Utility functions // Utility functions

View File

@ -44,7 +44,13 @@ namespace dropshell {
// |-- .template_info.env // |-- .template_info.env
// |-- (...other config files for specific server&service...) // |-- (...other config files for specific server&service...)
namespace filenames {
static const std::string template_info_env = ".template_info.env";
static const std::string service_env = "service.env";
static const std::string readme = "README.txt";
static const std::string server_json = "server.json";
static const std::string dropshell_json = "dropshell.json";
} // namespace filenames.
namespace localfile { namespace localfile {
// ~/.config/dropshell/dropshell.json // ~/.config/dropshell/dropshell.json

View File

@ -54,13 +54,12 @@ bool execute_ssh_command(const sSSHInfo & ssh_info, const sCommand & remote_comm
// class to hold a command to run on the remote server. // class to hold a command to run on the remote server.
class sCommand { class sCommand {
public: public:
sCommand(std::string directory_to_run_in, std::string command_to_run, const std::map<std::string, std::string> & env_vars, bool requires_root = false) : 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), mRequiresRoot(requires_root) {} mDir(directory_to_run_in), mCmd(command_to_run), mVars(env_vars) {}
std::string get_directory_to_run_in() const { return mDir; } std::string get_directory_to_run_in() const { return mDir; }
std::string get_command_to_run() const { return mCmd; } std::string get_command_to_run() const { return mCmd; }
const std::map<std::string, std::string>& get_env_vars() const { return mVars; } const std::map<std::string, std::string>& get_env_vars() const { return mVars; }
bool requires_root() const { return mRequiresRoot; }
void add_env_var(const std::string& key, const std::string& value) { mVars[key] = value; } void add_env_var(const std::string& key, const std::string& value) { mVars[key] = value; }
@ -72,7 +71,6 @@ class sCommand {
std::string makesafecmd(std::string bb64path, const std::string& command) const; std::string makesafecmd(std::string bb64path, const std::string& command) const;
private: private:
bool mRequiresRoot;
std::string mDir; std::string mDir;
std::string mCmd; std::string mCmd;
std::map<std::string, std::string> mVars; std::map<std::string, std::string> mVars;