diff --git a/source/src/commands/create-service.cpp b/source/src/commands/create-service.cpp index 32969b2..17f1a4a 100644 --- a/source/src/commands/create-service.cpp +++ b/source/src/commands/create-service.cpp @@ -2,6 +2,7 @@ #include "directories.hpp" #include "shared_commands.hpp" #include "templates.hpp" +#include "envmanager.hpp" #include #include "utils/utils.hpp" @@ -85,7 +86,9 @@ namespace dropshell return false; ordered_env_vars all_env_vars; - get_all_service_env_vars(server, service, all_env_vars); + envmanager env_manager(localfile::service_env(server,service)); + env_manager.load(); + env_manager.get_all_variables(all_env_vars); set_var(all_env_vars, "LOCAL_CONFIG_PATH", localpath::service(server, service)); set_var(all_env_vars, "LOCAL_TEMPLATE_PATH", tinfo.local_template_path().string()); diff --git a/source/src/commands/exec.cpp b/source/src/commands/exec.cpp deleted file mode 100644 index c97724c..0000000 --- a/source/src/commands/exec.cpp +++ /dev/null @@ -1,137 +0,0 @@ -#include "command_registry.hpp" -#include "config.hpp" -#include "utils/utils.hpp" -#include "utils/directories.hpp" -#include "utils/execute.hpp" -#include "shared_commands.hpp" -#include "servers.hpp" -#include "services.hpp" -#include "templates.hpp" -#include "utils/output.hpp" -#include - -namespace dropshell -{ - - int exec_handler(const CommandContext &ctx); - - static std::vector exec_name_list = {"exec"}; - - // Static registration - struct ExecCommandRegister - { - ExecCommandRegister() - { - CommandRegistry::instance().register_command({exec_name_list, - exec_handler, - shared_commands::std_autocomplete, - false, // hidden - true, // requires_config - true, // requires_install - 3, // min_args (server, service, command) - -1, // max_args (unlimited for command with args) - "exec SERVER SERVICE COMMAND [ARGS...]", - "Execute a command on a server within a service environment.", - R"( - - exec SERVER SERVICE COMMAND [ARGS...] Execute a command in the service's environment. - - This command runs a command on the remote server with the service's environment - variables loaded (including those from service.env and the usual variables). - The command is executed in the service's template directory context. - )"}); - } - } exec_command_register; - - int exec_handler(const CommandContext &ctx) - { - if (ctx.args.size() < 3) - { - error << "Server name, service name, and command are required" << std::endl; - return 1; - } - - std::string server = safearg(ctx.args, 0); - std::string service = safearg(ctx.args, 1); - std::string command = safearg(ctx.args, 2); - - // Collect any additional arguments for the command - std::vector command_args; - for (size_t i = 3; i < ctx.args.size(); ++i) - { - command_args.push_back(ctx.args[i]); - } - - // Validate server - ServerConfig server_env(server); - if (!server_env.is_valid()) - { - error << "Server " << server << " is not valid" << std::endl; - return 1; - } - - // Validate service name - if (!legal_service_name(service)) - { - error << "Service name contains illegal characters: " << service << std::endl; - return 1; - } - - // Get service info to validate it exists - LocalServiceInfo sinfo = get_service_info(server, service); - if (!SIvalid(sinfo)) - { - error << "Service " << service << " is not valid on server " << server << std::endl; - return 1; - } - - // Get the user for this service - std::string user = server_env.get_user_for_service(service); - - // Get all service environment variables - ordered_env_vars env_vars; - if (!get_all_service_env_vars(server, service, env_vars)) - { - error << "Failed to get environment variables for service " << service << std::endl; - return 1; - } - - // Add HOST_NAME like other commands do - set_var(env_vars, "HOST_NAME", server_env.get_SSH_HOST()); - - // Get the remote service template path for working directory - std::string remote_service_template_path = remotepath(server, user).service_template(service); - - // Build the command string with arguments - std::string full_command = command; - for (const auto &arg : command_args) - { - full_command += " " + quote(dequote(trim(arg))); - } - - // Create the command structure with environment variables - // Note: execute_ssh_command will automatically use bb64 to encode and execute this safely - sCommand scommand(remote_service_template_path, full_command, env_vars); - - // Execute the command on the remote server - info << "Executing command on " << server << "/" << service << ": " << command; - if (!command_args.empty()) - { - rawout << " with args:"; - for (const auto &arg : command_args) - rawout << " " << arg; - } - rawout << std::endl; - - bool success = execute_ssh_command(server_env.get_SSH_INFO(user), scommand, cMode::Interactive); - - if (!success) - { - error << "Command execution failed" << std::endl; - return 1; - } - - return 0; - } - -} // namespace dropshell \ No newline at end of file diff --git a/source/src/commands/install.cpp b/source/src/commands/install.cpp index d5f7ce1..867aefe 100644 --- a/source/src/commands/install.cpp +++ b/source/src/commands/install.cpp @@ -143,8 +143,8 @@ namespace dropshell // Validate service.env matches template service.env { - std::filesystem::path template_service_env = tinfo.local_template_path() / "config" / "service.env"; - std::filesystem::path template_info_env = tinfo.local_template_path() / "config" / ".template_info.env"; + std::filesystem::path template_service_env = tinfo.local_template_service_env_path(); //tinfo.local_template_path() / "config" / "service.env"; + std::filesystem::path template_info_env = tinfo.local_template_info_env_path(); //tinfo.local_template_path() / "config" / ".template_info.env"; std::string service_env_file = localfile::service_env(server, service); std::vector missing_vars; diff --git a/source/src/commands/ssh.cpp b/source/src/commands/ssh.cpp index 670e25f..3f27645 100644 --- a/source/src/commands/ssh.cpp +++ b/source/src/commands/ssh.cpp @@ -91,17 +91,7 @@ namespace dropshell return server_env.run_remote_template_command(service, "ssh", {}, false, {}, NULL); // explicitly supports interactive ssh! } - // ssh in without as ssh.sh script. - ordered_env_vars env_vars; - if (!get_all_service_env_vars(server, service, env_vars)) - { - error << "Failed to get all service env vars for " << service << std::endl; - return false; - } - set_var(env_vars, "HOST_NAME", server_env.get_SSH_HOST()); - std::string service_dir = remotepath(server, sinfo.user).service_template(service); - - return ssh_into_server(server, sinfo.user, env_vars, service_dir); + error << "No ssh script provided for the service "<second == "true"; @@ -74,7 +74,6 @@ namespace dropshell LocalServiceInfo get_service_info(const std::string &server_name, const std::string &service_name, bool skip_update) { - LocalServiceInfo service; if (server_name.empty() || service_name.empty()) return LocalServiceInfo(); @@ -82,6 +81,10 @@ namespace dropshell if (!legal_service_name(service_name)) return LocalServiceInfo(); + + LocalServiceInfo service; + template_info tinfo; + service.service_name = service_name; service.local_service_path = localpath::service(server_name, service_name); @@ -96,45 +99,54 @@ namespace dropshell } // now set the template name and path. - ordered_env_vars variables; - if (!get_all_service_env_vars(server_name, service_name, variables)) - return LocalServiceInfo(); - - { // confirm TEMPLATE is defined. + { // service.env variables. + ordered_env_vars variables; + envmanager env_manager(localfile::service_env(server_name, service_name)); + bool ok = env_manager.load(); + env_manager.get_all_variables(variables); + ASSERT(ok, "Failed to load env variables from "+localfile::service_env(server_name, service_name)); auto it = find_var(variables, "TEMPLATE"); if (it == variables.end()) { error << "TEMPLATE variable not defined in service " << service_name << " on server " << server_name << std::endl; + info << "Path is " << localfile::service_env(server_name, service_name) << std::endl; return LocalServiceInfo(); } service.template_name = it->second; - } - template_info tinfo = gTemplateManager().get_template_info(service.template_name,skip_update); - if (!tinfo.is_set()) - { - // Template not found - this means it's not available locally OR from registry - error << "Template '" << service.template_name << "' not found locally or in registry" << std::endl; - return LocalServiceInfo(); - } - - // Template is available (either locally or downloaded from registry) - service.local_template_path = tinfo.local_template_path(); - - { // set the user. - auto it = find_var(variables, "SSH_USER"); - if (it == variables.end()) + tinfo = gTemplateManager().get_template_info(service.template_name,skip_update); + if (!tinfo.is_set()) { - error << "SSH_USER variable not defined in service " << service_name << " on server " << server_name << std::endl; + // Template not found - this means it's not available locally OR from registry + error << "Template '" << service.template_name << "' not found locally or in registry" << std::endl; return LocalServiceInfo(); } - service.user = it->second; + + // Template is available (either locally or downloaded from registry) + service.local_template_path = tinfo.local_template_path(); + + { // set the user. + auto it = find_var(variables, "SSH_USER"); + if (it == variables.end()) + { + error << "SSH_USER variable not defined in service " << service_name << " on server " << server_name << std::endl; + return LocalServiceInfo(); + } + service.user = it->second; + } } - // set the host root and docker requirements. - service.requires_host_root = get_bool_variable(variables, "REQUIRES_HOST_ROOT"); - service.requires_docker = get_bool_variable(variables, "REQUIRES_DOCKER"); - service.requires_docker_root = get_bool_variable(variables, "REQUIRES_DOCKER_ROOT"); + // set the host root and docker requirements from the template_info.env + { // template_info.env variables. + ordered_env_vars template_variables; + envmanager template_env_manager(tinfo.local_template_info_env_path()); + template_env_manager.load(); + template_env_manager.get_all_variables(template_variables); + + service.requires_host_root = get_bool_variable(template_variables, "REQUIRES_HOST_ROOT"); + service.requires_docker = get_bool_variable(template_variables, "REQUIRES_DOCKER"); + service.requires_docker_root = get_bool_variable(template_variables, "REQUIRES_DOCKER_ROOT"); + } return service; } @@ -196,70 +208,70 @@ namespace dropshell return backups; } - bool get_all_service_env_vars(const std::string &server_name, const std::string &service_name, ordered_env_vars &all_env_vars) - { - clear_vars(all_env_vars); + // bool get_all_service_env_vars(const std::string &server_name, const std::string &service_name, ordered_env_vars &all_env_vars) + // { + // clear_vars(all_env_vars); - if (localpath::service(server_name, service_name).empty() || !fs::exists(localpath::service(server_name, service_name))) - { - error << "Service not found: " << service_name << " on server " << server_name << std::endl; - return false; - } + // if (localpath::service(server_name, service_name).empty() || !fs::exists(localpath::service(server_name, service_name))) + // { + // error << "Service not found: " << service_name << " on server " << server_name << std::endl; + // return false; + // } - // Lambda function to load environment variables from a file - auto load_env_file = [&all_env_vars](const std::string &file) - { - if (!file.empty() && std::filesystem::exists(file)) - { - ordered_env_vars env_vars; - envmanager env_manager(file); - env_manager.load(); - env_manager.get_all_variables(env_vars); - merge_vars(all_env_vars, env_vars); - } - else - warning << "Expected environment file not found: " << file << std::endl; - }; + // // Lambda function to load environment variables from a file + // auto load_env_file = [&all_env_vars](const std::string &file) + // { + // if (!file.empty() && std::filesystem::exists(file)) + // { + // ordered_env_vars env_vars; + // envmanager env_manager(file); + // env_manager.load(); + // env_manager.get_all_variables(env_vars); + // merge_vars(all_env_vars, env_vars); + // } + // else + // warning << "Expected environment file not found: " << file << std::endl; + // }; - // add in some simple variables first, as others below may depend on/use these in bash. - set_var(all_env_vars, "SERVER", server_name); - set_var(all_env_vars, "SERVICE", service_name); - set_var(all_env_vars, "DOCKER_CLI_HINTS", "false"); // turn off docker junk. + // // add in some simple variables first, as others below may depend on/use these in bash. + // set_var(all_env_vars, "SERVER", server_name); + // set_var(all_env_vars, "SERVICE", service_name); + // set_var(all_env_vars, "DOCKER_CLI_HINTS", "false"); // turn off docker junk. - // Load environment files - load_env_file(localfile::service_env(server_name, service_name)); + // // Load environment files + // load_env_file(localfile::service_env(server_name, service_name)); - std::string template_name = get_var(all_env_vars, "TEMPLATE"); - if (template_name.empty()) - { - error << "TEMPLATE variable not defined in service " << service_name << " on server " << server_name << std::endl; - return false; - } - auto tinfo = gTemplateManager().get_template_info(template_name, true); // skip updates. - if (!tinfo.is_set()) - { - // Template is not available locally or from registry - error << "Template '" << template_name << "' not found locally or in registry" << std::endl; - return false; - } - ASSERT(std::filesystem::exists(tinfo.local_template_info_env_path())); - load_env_file(tinfo.local_template_info_env_path()); + // std::string template_name = get_var(all_env_vars, "TEMPLATE"); + // if (template_name.empty()) + // { + // error << "TEMPLATE variable not defined in service " << service_name << " on server " << server_name << std::endl; + // return false; + // } + // auto tinfo = gTemplateManager().get_template_info(template_name, true); // skip updates. + // if (!tinfo.is_set()) + // { + // // Template is not available locally or from registry + // error << "Template '" << template_name << "' not found locally or in registry" << std::endl; + // return false; + // } + // ASSERT(std::filesystem::exists(tinfo.local_template_info_env_path())); + // load_env_file(tinfo.local_template_info_env_path()); - std::string user = get_var(all_env_vars, "SSH_USER"); - 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 in the "< get_used_commands(const std::string& server_name, const std::string& service_name); - // get all env vars for a given service - bool get_all_service_env_vars(const std::string& server_name, const std::string& service_name, ordered_env_vars& all_env_vars); - // list all backups for a given service (across all servers) std::set list_backups(const std::string& server_name, const std::string& service_name); diff --git a/source/src/templates.cpp b/source/src/templates.cpp index ca75c82..dee0091 100644 --- a/source/src/templates.cpp +++ b/source/src/templates.cpp @@ -891,6 +891,11 @@ For full documentation, see: dropshell help templates // mHash = hash_directory_recursive(local_template_path); } + std::filesystem::path template_info::local_template_service_env_path() + { + return mTemplateLocalPath / "config" / filenames::service_env ; + } + std::filesystem::path template_info::local_template_info_env_path() { return mTemplateLocalPath / filenames::template_info_env ; diff --git a/source/src/templates.hpp b/source/src/templates.hpp index f0077cc..f2f6249 100644 --- a/source/src/templates.hpp +++ b/source/src/templates.hpp @@ -26,6 +26,7 @@ class template_info { std::string name() const { return mTemplateName; } std::string locationID() const { return mLocationID; } std::filesystem::path local_template_path() const { return mTemplateLocalPath; } + std::filesystem::path local_template_service_env_path(); std::filesystem::path local_template_info_env_path(); bool template_valid() const { return mTemplateValid; }