From 763293c7d0cbfba1b07f653d74596847de07df47 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 24 May 2025 11:49:24 +1200 Subject: [PATCH] dropshell release 2025.0524.1149 --- .example/servers/localhost/_server.env | 2 +- source/src/commands/create-service.cpp | 25 +++++++++++++--- source/src/commands/install.cpp | 9 ++++++ source/src/commands/shared_commands.hpp | 1 + source/src/servers.cpp | 39 ++++++------------------- source/src/services.cpp | 6 ++-- source/src/templates.cpp | 12 ++++---- source/src/utils/directories.cpp | 16 ++++------ source/src/utils/directories.hpp | 8 ++++- source/src/utils/execute.hpp | 6 ++-- 10 files changed, 64 insertions(+), 60 deletions(-) diff --git a/.example/servers/localhost/_server.env b/.example/servers/localhost/_server.env index 2f15e36..14c9c51 100644 --- a/.example/servers/localhost/_server.env +++ b/.example/servers/localhost/_server.env @@ -1,5 +1,5 @@ SSH_ADDRESS=localhost SSH_PORT=22 -SSH_USER=$(whoami) +SSH_UNPRIVILEGED_USER=$(whoami) diff --git a/source/src/commands/create-service.cpp b/source/src/commands/create-service.cpp index fd152af..9c82dd2 100644 --- a/source/src/commands/create-service.cpp +++ b/source/src/commands/create-service.cpp @@ -152,7 +152,7 @@ namespace dropshell recursive_copy(tinfo.local_template_path() / "config", service_dir); // 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); template_info_env_file_out << "TEMPLATE_HASH=" << tinfo.hash() << std::endl; 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. - 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); 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; while (std::getline(template_service_env_file_in, line)) { @@ -239,6 +239,23 @@ namespace dropshell 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 dropshell \ No newline at end of file diff --git a/source/src/commands/install.cpp b/source/src/commands/install.cpp index 3b1d059..f10591a 100644 --- a/source/src/commands/install.cpp +++ b/source/src/commands/install.cpp @@ -70,6 +70,15 @@ namespace dropshell if (!SIvalid(service_info)) 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); diff --git a/source/src/commands/shared_commands.hpp b/source/src/commands/shared_commands.hpp index 0854e60..dbfd637 100644 --- a/source/src/commands/shared_commands.hpp +++ b/source/src/commands/shared_commands.hpp @@ -98,6 +98,7 @@ namespace dropshell // 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 merge_updated_service_template(const std::string &server_name, const std::string &service_name); } // namespace shared_commands } // namespace dropshell diff --git a/source/src/servers.cpp b/source/src/servers.cpp index 3ad9b37..07a5450 100644 --- a/source/src/servers.cpp +++ b/source/src/servers.cpp @@ -28,23 +28,22 @@ namespace dropshell if (server_name.empty()) return; - // Construct the full path to server.json - std::string server_env_path = localfile::server_json(server_name); + std::string server_json_path = localfile::server_json(server_name); // 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; } try { // 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()) { - 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; return; } @@ -96,7 +95,7 @@ namespace dropshell 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; } @@ -104,7 +103,7 @@ namespace dropshell } 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; mValid = false; @@ -334,30 +333,10 @@ namespace dropshell 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( remote_service_template_path, quote(script_path) + argstr + (silent ? " > /dev/null 2>&1" : ""), - env_vars, - run_as_root); + env_vars); if (sc.empty()) { @@ -427,7 +406,7 @@ namespace dropshell // 3. create a template server.env file in the server directory 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); server_env_file << "{" << std::endl; server_env_file << " \"SSH_HOST\": \"" << server_name << "\"," << std::endl; diff --git a/source/src/services.cpp b/source/src/services.cpp index 2f82929..4100d16 100644 --- a/source/src/services.cpp +++ b/source/src/services.cpp @@ -67,7 +67,7 @@ namespace dropshell auto it = variables.find(variable_name); 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 it->second == "true"; @@ -237,7 +237,7 @@ namespace dropshell if (user.empty()) { 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 "< std::string search_string = "TEMPLATE="; 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)) { - 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; } @@ -306,8 +306,8 @@ std::string template_name = std::filesystem::path(template_path).filename().string(); std::vector required_files = { - "config/service.env", - "config/.template_info.env", + "config/" + filenames::service_env, + "config/" + filenames::template_info_env, "install.sh", "uninstall.sh" }; @@ -331,8 +331,8 @@ // check TEMPLATE= line. std::map all_env_vars; std::vector env_files = { - "config/service.env", - "config/.template_info.env" + "config/" + filenames::service_env, + "config/" + filenames::template_info_env }; for (const auto& file : env_files) { { // load service.env from the service on this machine. diff --git a/source/src/utils/directories.cpp b/source/src/utils/directories.cpp index 6e3294c..71a0e9e 100644 --- a/source/src/utils/directories.cpp +++ b/source/src/utils/directories.cpp @@ -19,7 +19,7 @@ namespace localfile { // Try ~/.config/dropshell/dropshell.json std::string homedir = localpath::current_user_home(); 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 std::string(); @@ -27,18 +27,18 @@ namespace localfile { std::string server_json(const std::string &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 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 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() @@ -165,7 +165,7 @@ namespace localpath { 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")); } - // 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 diff --git a/source/src/utils/directories.hpp b/source/src/utils/directories.hpp index 12a9456..4a07648 100644 --- a/source/src/utils/directories.hpp +++ b/source/src/utils/directories.hpp @@ -44,7 +44,13 @@ namespace dropshell { // |-- .template_info.env // |-- (...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 { // ~/.config/dropshell/dropshell.json diff --git a/source/src/utils/execute.hpp b/source/src/utils/execute.hpp index f72b9fc..ca71734 100644 --- a/source/src/utils/execute.hpp +++ b/source/src/utils/execute.hpp @@ -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 sCommand { public: - sCommand(std::string directory_to_run_in, std::string command_to_run, const std::map & env_vars, bool requires_root = false) : - mDir(directory_to_run_in), mCmd(command_to_run), mVars(env_vars), mRequiresRoot(requires_root) {} + 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) {} std::string get_directory_to_run_in() const { return mDir; } std::string get_command_to_run() const { return mCmd; } const std::map& 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; } @@ -72,7 +71,6 @@ class sCommand { std::string makesafecmd(std::string bb64path, const std::string& command) const; private: - bool mRequiresRoot; std::string mDir; std::string mCmd; std::map mVars;