Add overrides.env support for per-location service env overrides
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include <libassert/assert.hpp>
|
||||
#include "utils/utils.hpp"
|
||||
#include "utils/service_env_validator.hpp"
|
||||
#include "utils/service_env_overrides.hpp"
|
||||
#include "services.hpp"
|
||||
|
||||
#include <fstream>
|
||||
@@ -230,6 +231,13 @@ namespace dropshell
|
||||
return false;
|
||||
}
|
||||
|
||||
// apply overrides from overrides.env (if present in server definition path)
|
||||
{
|
||||
auto changes = apply_overrides(server_name, service_name);
|
||||
for (const auto& c : changes)
|
||||
debug << "Override applied: " << c.key << "=" << c.new_val << std::endl;
|
||||
}
|
||||
|
||||
// check docker.
|
||||
if (service_info.requires_docker)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#include "templates.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <filesystem>
|
||||
@@ -32,12 +34,13 @@ struct EditCommandRegister {
|
||||
false, // requires_install
|
||||
0, // min_args (after command)
|
||||
2, // max_args (after command)
|
||||
"edit [SERVER] [SERVICE]",
|
||||
"Edit dropshell, server or service configuration",
|
||||
"edit [SERVER] [SERVICE] | edit override",
|
||||
"Edit dropshell, server, service, or override configuration",
|
||||
// heredoc
|
||||
R"(
|
||||
Edit dropshell, server or service configuration.
|
||||
edit edit the dropshell config.
|
||||
edit override edit the overrides.env for a server location.
|
||||
edit <server> edit the server config.
|
||||
edit <server> <service> edit the service config.
|
||||
)"
|
||||
@@ -241,12 +244,70 @@ int edit_service_config(const std::string &server, const std::string &service)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// edit override
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int edit_override()
|
||||
{
|
||||
auto paths = gConfig().get_local_server_definition_paths();
|
||||
if (paths.empty()) {
|
||||
error << "No server definition paths configured." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string chosen_path;
|
||||
if (paths.size() == 1) {
|
||||
chosen_path = paths[0];
|
||||
} else {
|
||||
// Multiple paths - ask user to choose with single keypress
|
||||
info << "Multiple server locations found. Choose one:" << std::endl;
|
||||
for (size_t i = 0; i < paths.size() && i < 9; ++i)
|
||||
info << " " << (i + 1) << ") " << paths[i] << std::endl;
|
||||
|
||||
info << "Enter choice [1-" << std::min(paths.size(), (size_t)9) << "]: " << std::flush;
|
||||
|
||||
// Read single keypress
|
||||
struct termios oldt, newt;
|
||||
tcgetattr(STDIN_FILENO, &oldt);
|
||||
newt = oldt;
|
||||
newt.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
||||
int ch = getchar();
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||
info << (char)ch << std::endl;
|
||||
|
||||
int idx = ch - '1';
|
||||
if (idx < 0 || idx >= (int)paths.size()) {
|
||||
error << "Invalid choice." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
chosen_path = paths[idx];
|
||||
}
|
||||
|
||||
std::string override_file = (std::filesystem::path(chosen_path) / filenames::overrides_env).string();
|
||||
|
||||
// Create with comment header if it doesn't exist
|
||||
if (!std::filesystem::exists(override_file)) {
|
||||
std::ofstream f(override_file);
|
||||
f << "# Overrides for all services in this server location." << std::endl;
|
||||
f << "# Variables set here will be forced into every service.env" << std::endl;
|
||||
f << "# during create-service and install." << std::endl;
|
||||
f << "#" << std::endl;
|
||||
f << "# Format is the same as service.env:" << std::endl;
|
||||
f << "# VARIABLE_NAME=\"value\"" << std::endl;
|
||||
f << std::endl;
|
||||
info << "Created new overrides file: " << override_file << std::endl;
|
||||
}
|
||||
|
||||
return edit_file(override_file, true) ? 0 : 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// edit command handler
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int edit_handler(const CommandContext& ctx) {
|
||||
// edit dropshell config
|
||||
if (ctx.args.size() < 1)
|
||||
if (ctx.args.size() < 1)
|
||||
{
|
||||
if (ctx.command=="create-config")
|
||||
{
|
||||
@@ -258,6 +319,10 @@ int edit_handler(const CommandContext& ctx) {
|
||||
return edit_config();
|
||||
}
|
||||
|
||||
// edit override - check before server/service dispatch
|
||||
if (safearg(ctx.args, 0) == "override")
|
||||
return edit_override();
|
||||
|
||||
// edit server config
|
||||
if (ctx.args.size() < 2) {
|
||||
edit_server(safearg(ctx.args,0));
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "services.hpp"
|
||||
#include "utils/output.hpp"
|
||||
#include "utils/service_env_validator.hpp"
|
||||
#include "utils/service_env_overrides.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
@@ -147,6 +148,13 @@ namespace dropshell
|
||||
}
|
||||
}
|
||||
|
||||
// Apply overrides from overrides.env (if present in server definition path)
|
||||
{
|
||||
auto changes = apply_overrides(server, service);
|
||||
for (const auto& c : changes)
|
||||
warning << "Override: " << c.key << " changed from \"" << c.old_val << "\" to \"" << c.new_val << "\"" << std::endl;
|
||||
}
|
||||
|
||||
// ── Stage new template + config to _staging folder on remote ──
|
||||
std::string staging_path = remote_service_path + "/_staging";
|
||||
std::string staging_template = staging_path + "/template";
|
||||
|
||||
@@ -43,6 +43,14 @@ namespace dropshell
|
||||
return localpath::agent_remote() + "/agent.hash";
|
||||
}
|
||||
|
||||
std::string overrides_env_for_server(const std::string &server_name)
|
||||
{
|
||||
std::string serverpath = localpath::server(server_name);
|
||||
if (serverpath.empty())
|
||||
return "";
|
||||
return (fs::path(get_parent(serverpath)) / filenames::overrides_env).string();
|
||||
}
|
||||
|
||||
} // namespace localfile
|
||||
|
||||
std::string get_local_agent_hash()
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace dropshell {
|
||||
static const std::string ds_run = "ds_run.sh";
|
||||
static const std::string template_paths_json = "template_paths.json";
|
||||
static const std::string dropshell_templates_list = "dropshell-templates.list";
|
||||
static const std::string overrides_env = "overrides.env";
|
||||
} // namespace filenames.
|
||||
|
||||
namespace localfile {
|
||||
@@ -51,6 +52,7 @@ namespace dropshell {
|
||||
std::string service_env(const std::string &server_name, const std::string &service_name);
|
||||
std::string bb64();
|
||||
std::string agent_hash(); // Returns path to agent.hash file
|
||||
std::string overrides_env_for_server(const std::string &server_name); // overrides.env in server's definition path
|
||||
} // namespace localfile
|
||||
|
||||
// Get the content of the local agent hash (empty string if not found)
|
||||
|
||||
51
source/src/utils/service_env_overrides.cpp
Normal file
51
source/src/utils/service_env_overrides.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#include "service_env_overrides.hpp"
|
||||
#include "directories.hpp"
|
||||
#include "envmanager.hpp"
|
||||
#include "service_env_validator.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
std::vector<OverrideChange> apply_overrides(
|
||||
const std::string& server_name,
|
||||
const std::string& service_name)
|
||||
{
|
||||
std::vector<OverrideChange> changes;
|
||||
|
||||
std::string overrides_path = localfile::overrides_env_for_server(server_name);
|
||||
if (overrides_path.empty() || !std::filesystem::exists(overrides_path))
|
||||
return changes;
|
||||
|
||||
std::string service_env_path = localfile::service_env(server_name, service_name);
|
||||
if (service_env_path.empty() || !std::filesystem::exists(service_env_path))
|
||||
return changes;
|
||||
|
||||
// Load overrides
|
||||
envmanager overrides(overrides_path);
|
||||
if (!overrides.load())
|
||||
return changes;
|
||||
|
||||
ordered_env_vars override_vars;
|
||||
overrides.get_all_variables(override_vars);
|
||||
if (override_vars.empty())
|
||||
return changes;
|
||||
|
||||
// Load current service env
|
||||
envmanager service_env(service_env_path);
|
||||
if (!service_env.load())
|
||||
return changes;
|
||||
|
||||
// Apply each override
|
||||
for (const auto& [key, new_val] : override_vars) {
|
||||
std::string current_val = service_env.get_variable(key);
|
||||
if (current_val != new_val) {
|
||||
set_env_variable(service_env_path, key, new_val);
|
||||
changes.push_back({key, current_val, new_val});
|
||||
}
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
} // namespace dropshell
|
||||
24
source/src/utils/service_env_overrides.hpp
Normal file
24
source/src/utils/service_env_overrides.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef SERVICE_ENV_OVERRIDES_HPP
|
||||
#define SERVICE_ENV_OVERRIDES_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
struct OverrideChange {
|
||||
std::string key;
|
||||
std::string old_val;
|
||||
std::string new_val;
|
||||
};
|
||||
|
||||
// Apply overrides from overrides.env (in the server's definition path) to a service's service.env.
|
||||
// Returns a list of changes that were made.
|
||||
// If no overrides.env exists, returns empty (no-op).
|
||||
std::vector<OverrideChange> apply_overrides(
|
||||
const std::string& server_name,
|
||||
const std::string& service_name);
|
||||
|
||||
} // namespace dropshell
|
||||
|
||||
#endif // SERVICE_ENV_OVERRIDES_HPP
|
||||
Reference in New Issue
Block a user