service.env validation
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
#include "autogen/_agent-remote.hpp"
|
#include "autogen/_agent-remote.hpp"
|
||||||
#include "services.hpp"
|
#include "services.hpp"
|
||||||
#include "utils/output.hpp"
|
#include "utils/output.hpp"
|
||||||
|
#include "utils/env_validator.hpp"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -150,6 +151,41 @@ namespace dropshell
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate service.env matches template service.env
|
||||||
|
{
|
||||||
|
std::filesystem::path template_service_env = tinfo.local_template_path() / "config" / "service.env";
|
||||||
|
std::string service_env_file = localfile::service_env(server, service);
|
||||||
|
|
||||||
|
std::vector<std::string> missing_vars;
|
||||||
|
std::vector<std::string> extra_vars;
|
||||||
|
|
||||||
|
if (!validate_and_fix_service_env(template_service_env.string(), service_env_file, missing_vars, extra_vars))
|
||||||
|
{
|
||||||
|
error << "Service environment file validation failed for " << service << std::endl;
|
||||||
|
|
||||||
|
if (!missing_vars.empty()) {
|
||||||
|
error << "Missing variables (added to service.env): ";
|
||||||
|
for (size_t i = 0; i < missing_vars.size(); ++i) {
|
||||||
|
error << missing_vars[i];
|
||||||
|
if (i < missing_vars.size() - 1) error << ", ";
|
||||||
|
}
|
||||||
|
error << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!extra_vars.empty()) {
|
||||||
|
error << "Extra variables (commented out in service.env): ";
|
||||||
|
for (size_t i = 0; i < extra_vars.size(); ++i) {
|
||||||
|
error << extra_vars[i];
|
||||||
|
if (i < extra_vars.size() - 1) error << ", ";
|
||||||
|
}
|
||||||
|
error << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
error << "Please run 'dropshell edit " << server << " " << service << "' to review and fix the service.env file" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Run install script
|
// Run install script
|
||||||
{
|
{
|
||||||
info << "Running " << service_info.template_name << " install script on " << server << "..." << std::endl;
|
info << "Running " << service_info.template_name << " install script on " << server << "..." << std::endl;
|
||||||
|
145
source/src/utils/env_validator.cpp
Normal file
145
source/src/utils/env_validator.cpp
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
#include "env_validator.hpp"
|
||||||
|
#include "envmanager.hpp"
|
||||||
|
#include "ordered_env.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
#include "output.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace dropshell {
|
||||||
|
|
||||||
|
bool validate_and_fix_service_env(
|
||||||
|
const std::string& template_service_env_path,
|
||||||
|
const std::string& service_env_path,
|
||||||
|
std::vector<std::string>& missing_vars,
|
||||||
|
std::vector<std::string>& extra_vars
|
||||||
|
) {
|
||||||
|
missing_vars.clear();
|
||||||
|
extra_vars.clear();
|
||||||
|
|
||||||
|
// Load template service.env
|
||||||
|
envmanager template_env(template_service_env_path);
|
||||||
|
if (!template_env.load()) {
|
||||||
|
error << "Failed to load template service.env from: " << template_service_env_path << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ordered_env_vars template_vars;
|
||||||
|
template_env.get_all_variables(template_vars);
|
||||||
|
|
||||||
|
// Create a set of template variable names for quick lookup
|
||||||
|
std::set<std::string> template_var_names;
|
||||||
|
for (const auto& [key, value] : template_vars) {
|
||||||
|
template_var_names.insert(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load service service.env
|
||||||
|
envmanager service_env(service_env_path);
|
||||||
|
if (!service_env.load()) {
|
||||||
|
error << "Failed to load service service.env from: " << service_env_path << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ordered_env_vars service_vars;
|
||||||
|
service_env.get_all_variables(service_vars);
|
||||||
|
|
||||||
|
// Create a set of service variable names for quick lookup
|
||||||
|
std::set<std::string> service_var_names;
|
||||||
|
for (const auto& [key, value] : service_vars) {
|
||||||
|
service_var_names.insert(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find missing variables (in template but not in service)
|
||||||
|
for (const auto& template_var_name : template_var_names) {
|
||||||
|
if (service_var_names.find(template_var_name) == service_var_names.end()) {
|
||||||
|
missing_vars.push_back(template_var_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find extra variables (in service but not in template)
|
||||||
|
for (const auto& service_var_name : service_var_names) {
|
||||||
|
if (template_var_names.find(service_var_name) == template_var_names.end()) {
|
||||||
|
extra_vars.push_back(service_var_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no differences, validation passes
|
||||||
|
if (missing_vars.empty() && extra_vars.empty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are differences - need to fix the service.env file
|
||||||
|
debug << "Fixing service.env file: " << service_env_path << std::endl;
|
||||||
|
|
||||||
|
// Read the original file line by line
|
||||||
|
std::ifstream infile(service_env_path);
|
||||||
|
if (!infile.is_open()) {
|
||||||
|
error << "Failed to open service.env for reading: " << service_env_path << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(infile, line)) {
|
||||||
|
lines.push_back(line);
|
||||||
|
}
|
||||||
|
infile.close();
|
||||||
|
|
||||||
|
// Process lines and comment out extra variables
|
||||||
|
std::set<std::string> extra_vars_set(extra_vars.begin(), extra_vars.end());
|
||||||
|
for (auto& line : lines) {
|
||||||
|
std::string trimmed = trim(line);
|
||||||
|
|
||||||
|
// Skip empty lines and comments
|
||||||
|
if (trimmed.empty() || trimmed[0] == '#') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this line defines a variable
|
||||||
|
size_t pos = trimmed.find('=');
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
std::string key = trim(trimmed.substr(0, pos));
|
||||||
|
key = dequote(key);
|
||||||
|
|
||||||
|
// If this is an extra variable, comment it out
|
||||||
|
if (extra_vars_set.find(key) != extra_vars_set.end()) {
|
||||||
|
// Only comment out if not already commented
|
||||||
|
if (line[0] != '#') {
|
||||||
|
line = "# " + line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add missing variables at the end
|
||||||
|
if (!missing_vars.empty()) {
|
||||||
|
lines.push_back("");
|
||||||
|
lines.push_back("# Variables added from template update:");
|
||||||
|
for (const auto& var_name : missing_vars) {
|
||||||
|
// Get the value from the template
|
||||||
|
std::string value = get_var(template_vars, var_name);
|
||||||
|
lines.push_back(var_name + "=" + quote(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the modified file back
|
||||||
|
std::ofstream outfile(service_env_path);
|
||||||
|
if (!outfile.is_open()) {
|
||||||
|
error << "Failed to open service.env for writing: " << service_env_path << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& l : lines) {
|
||||||
|
outfile << l << std::endl;
|
||||||
|
}
|
||||||
|
outfile.close();
|
||||||
|
|
||||||
|
// Validation failed because we had to make changes
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dropshell
|
27
source/src/utils/env_validator.hpp
Normal file
27
source/src/utils/env_validator.hpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef ENV_VALIDATOR_HPP
|
||||||
|
#define ENV_VALIDATOR_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace dropshell {
|
||||||
|
|
||||||
|
// Validates that a service's service.env file matches the template's service.env file
|
||||||
|
// Returns true if validation passes
|
||||||
|
// Returns false if there are mismatches (and fixes them by adding missing vars and commenting out extras)
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// template_service_env_path: Full path to the template's service.env file
|
||||||
|
// service_env_path: Full path to the service's service.env file
|
||||||
|
// missing_vars: Output parameter - list of variable names that were missing and added
|
||||||
|
// extra_vars: Output parameter - list of variable names that were extra and commented out
|
||||||
|
bool validate_and_fix_service_env(
|
||||||
|
const std::string& template_service_env_path,
|
||||||
|
const std::string& service_env_path,
|
||||||
|
std::vector<std::string>& missing_vars,
|
||||||
|
std::vector<std::string>& extra_vars
|
||||||
|
);
|
||||||
|
|
||||||
|
} // namespace dropshell
|
||||||
|
|
||||||
|
#endif // ENV_VALIDATOR_HPP
|
Reference in New Issue
Block a user