docs: Add 1 and update 5 files
This commit is contained in:
@@ -22,6 +22,8 @@ template-name/
|
||||
├── destroy.sh # OPTIONAL: Destroy service and data
|
||||
├── ssh.sh # OPTIONAL: SSH into service container
|
||||
├── ports.sh # OPTIONAL: List exposed ports
|
||||
├── check-config.sh # OPTIONAL: Validate configuration (for check-config command)
|
||||
├── reload-config.sh # OPTIONAL: Hot-reload configuration (for reload-config command)
|
||||
└── README.txt # OPTIONAL: Template documentation
|
||||
```
|
||||
|
||||
|
||||
195
source/src/commands/config.cpp
Normal file
195
source/src/commands/config.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
#include "command_registry.hpp"
|
||||
#include "config.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
#include "utils/directories.hpp"
|
||||
#include "shared_commands.hpp"
|
||||
#include "servers.hpp"
|
||||
#include "services.hpp"
|
||||
#include "utils/output.hpp"
|
||||
|
||||
namespace dropshell
|
||||
{
|
||||
|
||||
int check_config_handler(const CommandContext &ctx);
|
||||
int reload_config_handler(const CommandContext &ctx);
|
||||
|
||||
static std::vector<std::string> check_config_name_list = {"check-config", "check"};
|
||||
static std::vector<std::string> reload_config_name_list = {"reload-config", "reload"};
|
||||
|
||||
// Static registration for check-config
|
||||
struct CheckConfigCommandRegister
|
||||
{
|
||||
CheckConfigCommandRegister()
|
||||
{
|
||||
CommandRegistry::instance().register_command({check_config_name_list,
|
||||
check_config_handler,
|
||||
shared_commands::std_autocomplete,
|
||||
false, // hidden
|
||||
true, // requires_config
|
||||
true, // requires_install
|
||||
2, // min_args (after command)
|
||||
2, // max_args (after command)
|
||||
"check-config SERVER SERVICE",
|
||||
"Sync config and validate it on the remote server (optional template command)",
|
||||
R"(
|
||||
|
||||
check-config SERVER SERVICE Syncs the configuration to the remote server and runs
|
||||
the template's check-config.sh script to validate the config.
|
||||
|
||||
This is useful for validating configuration changes before reloading.
|
||||
The service is NOT restarted or modified - only config validation is performed.
|
||||
|
||||
Note: This command is optional - templates must implement check-config.sh to support it.
|
||||
)"});
|
||||
}
|
||||
} check_config_command_register;
|
||||
|
||||
// Static registration for reload-config
|
||||
struct ReloadConfigCommandRegister
|
||||
{
|
||||
ReloadConfigCommandRegister()
|
||||
{
|
||||
CommandRegistry::instance().register_command({reload_config_name_list,
|
||||
reload_config_handler,
|
||||
shared_commands::std_autocomplete,
|
||||
false, // hidden
|
||||
true, // requires_config
|
||||
true, // requires_install
|
||||
2, // min_args (after command)
|
||||
2, // max_args (after command)
|
||||
"reload-config SERVER SERVICE",
|
||||
"Sync config and hot-reload it on the remote server (optional template command)",
|
||||
R"(
|
||||
|
||||
reload-config SERVER SERVICE Syncs the configuration to the remote server and runs
|
||||
the template's reload-config.sh script to hot-reload the config.
|
||||
|
||||
This is useful for applying configuration changes without restarting the service.
|
||||
For example, Caddy can reload its config without dropping connections.
|
||||
|
||||
Note: This command is optional - templates must implement reload-config.sh to support it.
|
||||
)"});
|
||||
}
|
||||
} reload_config_command_register;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// check_config implementation
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool check_config_service(const std::string &server, const std::string &service)
|
||||
{
|
||||
if (gConfig().is_server_disabled(server))
|
||||
{
|
||||
warning << "Server '" << server << "' is disabled." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ServerConfig server_env(server);
|
||||
if (!server_env.is_valid())
|
||||
{
|
||||
error << "Server " << server << " is not valid" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!legal_service_name(service))
|
||||
{
|
||||
error << "Service name contains illegal characters: " << service << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sync configuration to remote
|
||||
info << "Syncing configuration for " << service << " on " << server << "..." << std::endl;
|
||||
if (!shared_commands::rsync_service_config(server_env, service, false))
|
||||
{
|
||||
error << "Failed to sync configuration" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Run check script
|
||||
info << "Running config check..." << std::endl;
|
||||
bool success = server_env.run_remote_template_command(service, "check-config", {}, false, {}, nullptr);
|
||||
|
||||
if (success)
|
||||
{
|
||||
info << "Configuration check passed for " << service << " on " << server << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
error << "Configuration check failed for " << service << " on " << server << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
int check_config_handler(const CommandContext &ctx)
|
||||
{
|
||||
if (ctx.args.size() < 2)
|
||||
{
|
||||
error << "Server name and service name are both required" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string server = safearg(ctx.args, 0);
|
||||
std::string service = safearg(ctx.args, 1);
|
||||
|
||||
return check_config_service(server, service) ? 0 : 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// reload_config implementation
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool reload_config_service(const std::string &server, const std::string &service)
|
||||
{
|
||||
if (gConfig().is_server_disabled(server))
|
||||
{
|
||||
warning << "Server '" << server << "' is disabled." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ServerConfig server_env(server);
|
||||
if (!server_env.is_valid())
|
||||
{
|
||||
error << "Server " << server << " is not valid" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!legal_service_name(service))
|
||||
{
|
||||
error << "Service name contains illegal characters: " << service << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sync configuration to remote
|
||||
info << "Syncing configuration for " << service << " on " << server << "..." << std::endl;
|
||||
if (!shared_commands::rsync_service_config(server_env, service, false))
|
||||
{
|
||||
error << "Failed to sync configuration" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Run reload script
|
||||
info << "Reloading configuration..." << std::endl;
|
||||
bool success = server_env.run_remote_template_command(service, "reload-config", {}, false, {}, nullptr);
|
||||
|
||||
if (success)
|
||||
{
|
||||
info << "Configuration reloaded for " << service << " on " << server << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
error << "Failed to reload configuration for " << service << " on " << server << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
int reload_config_handler(const CommandContext &ctx)
|
||||
{
|
||||
if (ctx.args.size() < 2)
|
||||
{
|
||||
error << "Server name and service name are both required" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string server = safearg(ctx.args, 0);
|
||||
std::string service = safearg(ctx.args, 1);
|
||||
|
||||
return reload_config_service(server, service) ? 0 : 1;
|
||||
}
|
||||
|
||||
} // namespace dropshell
|
||||
@@ -145,6 +145,8 @@ int help_handler(const CommandContext& ctx) {
|
||||
info << std::endl;
|
||||
show_command("start");
|
||||
show_command("stop");
|
||||
show_command("check-config");
|
||||
show_command("reload-config");
|
||||
info << std::endl;
|
||||
show_command("disable");
|
||||
show_command("enable");
|
||||
|
||||
@@ -113,31 +113,10 @@ namespace dropshell
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create service directory
|
||||
std::string mkdir_cmd = "mkdir -p " + quote(remote_service_path);
|
||||
if (!execute_ssh_command(server_env.get_SSH_INFO(user), sCommand("", mkdir_cmd, {}), cMode::Silent))
|
||||
// Sync template and config files to remote
|
||||
if (!shared_commands::rsync_service_config(server_env, service, false))
|
||||
{
|
||||
std::cerr << "Failed to create service directory " << remote_service_path << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy template files
|
||||
debug << "Copying: [LOCAL] " << tinfo.local_template_path() << std::endl
|
||||
<< std::string(8, ' ') << "[REMOTE] " << remotepath(server,user).service_template(service) << "/" << std::endl;
|
||||
if (!shared_commands::rsync_tree_to_remote(tinfo.local_template_path().string(), remotepath(server,user).service_template(service),
|
||||
server_env, false, service_info.user))
|
||||
{
|
||||
std::cerr << "Failed to copy template files using rsync" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy service files
|
||||
debug << "Copying: [LOCAL] " << localpath::service(server, service) << std::endl
|
||||
<< std::string(8, ' ') << "[REMOTE] " << remotepath(server,user).service_config(service) << std::endl;
|
||||
if (!shared_commands::rsync_tree_to_remote(localpath::service(server, service), remotepath(server,user).service_config(service),
|
||||
server_env, false, service_info.user))
|
||||
{
|
||||
std::cerr << "Failed to copy service files using rsync" << std::endl;
|
||||
error << "Failed to sync service configuration to remote" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "directories.hpp"
|
||||
#include "services.hpp"
|
||||
#include "servers.hpp"
|
||||
#include "templates.hpp"
|
||||
#include "utils/output.hpp"
|
||||
#include "utils/execute.hpp"
|
||||
#include "transwarp.hpp"
|
||||
@@ -94,6 +95,71 @@ namespace dropshell
|
||||
return execute_local_command("", rsync_cmd, {}, nullptr, (silent ? cMode::Silent : cMode::Defaults));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// rsync_service_config : SHARED COMMAND
|
||||
// Syncs both template and service config to remote server
|
||||
// Used by install, check-config, reload-config
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool rsync_service_config(
|
||||
const ServerConfig &server_env,
|
||||
const std::string &service,
|
||||
bool silent)
|
||||
{
|
||||
std::string server = server_env.get_server_name();
|
||||
LocalServiceInfo service_info = get_service_info(server, service);
|
||||
|
||||
if (!SIvalid(service_info))
|
||||
{
|
||||
error << "Service information not valid for " << service << " on " << server << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string user = service_info.user;
|
||||
std::string remote_service_path = remotepath(server, user).service(service);
|
||||
|
||||
// Ensure service directory exists
|
||||
std::string mkdir_cmd = "mkdir -p " + quote(remote_service_path);
|
||||
if (!execute_ssh_command(server_env.get_SSH_INFO(user), sCommand("", mkdir_cmd, {}), cMode::Silent))
|
||||
{
|
||||
error << "Failed to create service directory " << remote_service_path << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get template info
|
||||
template_info tinfo = gTemplateManager().get_template_info(service_info.template_name);
|
||||
if (!tinfo.is_set() || !tinfo.template_valid())
|
||||
{
|
||||
error << "Template is not valid: " << service_info.template_name << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy template files
|
||||
if (!silent) {
|
||||
debug << "Copying: [LOCAL] " << tinfo.local_template_path() << std::endl
|
||||
<< std::string(8, ' ') << "[REMOTE] " << remotepath(server, user).service_template(service) << "/" << std::endl;
|
||||
}
|
||||
if (!rsync_tree_to_remote(tinfo.local_template_path().string(), remotepath(server, user).service_template(service),
|
||||
server_env, silent, user))
|
||||
{
|
||||
error << "Failed to copy template files using rsync" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy service config files
|
||||
if (!silent) {
|
||||
debug << "Copying: [LOCAL] " << localpath::service(server, service) << std::endl
|
||||
<< std::string(8, ' ') << "[REMOTE] " << remotepath(server, user).service_config(service) << std::endl;
|
||||
}
|
||||
if (!rsync_tree_to_remote(localpath::service(server, service), remotepath(server, user).service_config(service),
|
||||
server_env, silent, user))
|
||||
{
|
||||
error << "Failed to copy service config files using rsync" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// get_arch : SHARED COMMAND
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -66,6 +66,13 @@ namespace dropshell
|
||||
bool silent,
|
||||
std::string user);
|
||||
|
||||
// Rsync service configuration (template + config) to remote server
|
||||
// Used by install, check-config, reload-config
|
||||
bool rsync_service_config(
|
||||
const ServerConfig &server_env,
|
||||
const std::string &service,
|
||||
bool silent = false);
|
||||
|
||||
std::string get_arch();
|
||||
|
||||
std::map<std::string, ServiceStatus> get_all_services_status(const ServerConfig & server_env, bool* agent_match = nullptr);
|
||||
|
||||
Reference in New Issue
Block a user