restore partially implemented.
This commit is contained in:
parent
71cb39d82e
commit
029187c0aa
@ -92,7 +92,7 @@ void dropshell::autocomplete_list_commands()
|
|||||||
if (dropshell::get_global_config()->is_config_set())
|
if (dropshell::get_global_config()->is_config_set())
|
||||||
commands.merge(std::set<std::string>{
|
commands.merge(std::set<std::string>{
|
||||||
"server","templates","create-service","create-template","create-server","edit","ssh",
|
"server","templates","create-service","create-template","create-server","edit","ssh",
|
||||||
"view" // only if we have a config.
|
"list" // only if we have a config.
|
||||||
});
|
});
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
std::cout << command << std::endl;
|
std::cout << command << std::endl;
|
||||||
|
@ -32,7 +32,7 @@ void print_help() {
|
|||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << "Service commands: (if no service is specified, all services for the server are affected)" << std::endl;
|
std::cout << "Service commands: (if no service is specified, all services for the server are affected)" << std::endl;
|
||||||
std::cout << " install SERVER [SERVICE] Install/reinstall/update service(s). Non-destructive." << std::endl;
|
std::cout << " install SERVER [SERVICE] Install/reinstall/update service(s). Non-destructive." << std::endl;
|
||||||
std::cout << " view [SERVER] [SERVICE] View status/details of all servers/server/service." << std::endl;
|
std::cout << " list [SERVER] [SERVICE] List status/details of all servers/server/service." << std::endl;
|
||||||
std::cout << " edit [SERVER] [SERVICE] Edit the configuration of dropshell/server/service." << std::endl;
|
std::cout << " edit [SERVER] [SERVICE] Edit the configuration of dropshell/server/service." << std::endl;
|
||||||
std::cout << " COMMAND SERVER [SERVICE] Run a command on service(s)." << std::endl;
|
std::cout << " COMMAND SERVER [SERVICE] Run a command on service(s)." << std::endl;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
@ -112,7 +112,7 @@ int main(int argc, char* argv[]) {
|
|||||||
std::cout << "["<< dir << "] ";
|
std::cout << "["<< dir << "] ";
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
if (cmd == "server" || cmd == "servers" || cmd == "view" || cmd == "views" || cmd == "v")
|
if (cmd == "server" || cmd == "servers" || cmd == "list" || cmd == "view")
|
||||||
switch (argc)
|
switch (argc)
|
||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -16,6 +16,10 @@ namespace dropshell {
|
|||||||
|
|
||||||
namespace main_commands {
|
namespace main_commands {
|
||||||
|
|
||||||
|
|
||||||
|
static const std::string magic_string = "-_-";
|
||||||
|
|
||||||
|
|
||||||
int init(const std::vector<std::string> &args)
|
int init(const std::vector<std::string> &args)
|
||||||
{
|
{
|
||||||
dropshell::config *cfg = dropshell::get_global_config();
|
dropshell::config *cfg = dropshell::get_global_config();
|
||||||
@ -52,8 +56,8 @@ int init(const std::vector<std::string> &args)
|
|||||||
|
|
||||||
int restore(const std::vector<std::string> &args)
|
int restore(const std::vector<std::string> &args)
|
||||||
{
|
{
|
||||||
if (args.size() < 3) {
|
if (args.size() < 4) {
|
||||||
std::cerr << "Error: restore command requires a directory argument" << std::endl;
|
std::cerr << "Error: not enough arguments. dropshell restore <server> <service> <backup-file>" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,30 +71,63 @@ int restore(const std::vector<std::string> &args)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! std::filesystem::exists(backup_file)) {
|
std::string local_backups_dir = get_local_backup_path();
|
||||||
std::cerr << "Error: Backup file not found" << std::endl;
|
std::string local_backup_file_path = (std::filesystem::path(local_backups_dir) / backup_file).string();
|
||||||
|
|
||||||
|
|
||||||
|
if (! std::filesystem::exists(local_backup_file_path)) {
|
||||||
|
std::cerr << "Error: Backup file not found at " << local_backup_file_path << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// backup_file is in format: server_name-template_name-service_name-YYYY-MM-DD_HH-MM-SS.tgz
|
|
||||||
// count '-' in backup_file
|
// split the backup filename into parts based on the magic string
|
||||||
int dash_count = std::count(backup_file.begin(), backup_file.end(), '-');
|
std::vector<std::string> parts = dropshell::split(backup_file, magic_string);
|
||||||
if (dash_count != 3) {
|
if (parts.size() != 4) {
|
||||||
std::cerr << "Error: Backup file format is incompatible, - in one of the names?" << std::endl;
|
std::cerr << "Error: Backup file format is incompatible, - in one of the names?" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string backup_server_name = parts[0];
|
||||||
|
std::string backup_template_name = parts[1];
|
||||||
|
std::string backup_service_name = parts[2];
|
||||||
|
std::string backup_datetime = parts[3];
|
||||||
|
|
||||||
|
if (backup_template_name != service_info.template_name) {
|
||||||
|
std::cerr << "Error: Backup template does not match service template. Can't restore." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string nicedate = std::string(backup_datetime).substr(0, 10);
|
||||||
|
|
||||||
|
std::cout << "Restoring " << nicedate << " backup of " << backup_template_name << " taken from "<<backup_server_name<<", onto "<<server_name<<std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "*** ALL DATA FOR "<<server_name<<"/"<<service_name<<" WILL BE OVERWRITTEN! ***"<<std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "Are you sure you want to continue? (y/n)" << std::endl;
|
||||||
|
char confirm;
|
||||||
|
std::cin >> confirm;
|
||||||
|
if (confirm != 'y') {
|
||||||
|
std::cout << "Restore cancelled." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the restore script
|
||||||
|
std::cout << "OK, here goes..." << std::endl;
|
||||||
|
std::cout << "1) Backing up existing service... " << std::flush;
|
||||||
|
|
||||||
|
std::vector<std::string> backup_args = {"dropshell","backup",server_name, service_name};
|
||||||
|
if (!backup(backup_args,true)) // silent=true
|
||||||
|
{
|
||||||
|
std::cerr << std::endl;
|
||||||
|
std::cerr << "Error: Backup failed, restore aborted." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
std::cout << "Backup complete." << std::endl;
|
||||||
|
|
||||||
|
std::cout << "2) Restoring service from backup..." << std::endl;
|
||||||
|
|
||||||
|
|
||||||
// if (service_info.template_name != backup_template_name) {
|
// run the restore script
|
||||||
// std::cerr << "Error: Backup template does not match service template. Can't restore." << std::endl;
|
|
||||||
// return 1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// std::string restore_cmd = "tar -xzvf " + backup_file + " -C " + service_info.path;
|
|
||||||
// std::string restore_cmd = "tar -xzvf " + backup_file + " -C " + service_info.path;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +147,12 @@ bool name_breaks_backups(std::string name)
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Backup the service.
|
// Backup the service.
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
int backup(const std::vector<std::string> & args) {
|
int backup(const std::vector<std::string> & args, bool silent) {
|
||||||
|
if (args.size() < 4) {
|
||||||
|
std::cerr << "Error: backup command requires a server name and service name" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
std::string server_name = args[2];
|
std::string server_name = args[2];
|
||||||
std::string service_name = args[3];
|
std::string service_name = args[3];
|
||||||
|
|
||||||
@ -126,7 +168,7 @@ int backup(const std::vector<std::string> & args) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string command = "backup";
|
const std::string command = "backup";
|
||||||
|
|
||||||
if (!template_command_exists(service_info.template_name, command)) {
|
if (!template_command_exists(service_info.template_name, command)) {
|
||||||
std::cout << "No backup script for " << service_info.template_name << std::endl;
|
std::cout << "No backup script for " << service_info.template_name << std::endl;
|
||||||
@ -135,12 +177,12 @@ int backup(const std::vector<std::string> & args) {
|
|||||||
|
|
||||||
// Check if basic installed stuff is in place.
|
// Check if basic installed stuff is in place.
|
||||||
std::string remote_service_template_path = get_remote_service_template_path(server_name, service_name);
|
std::string remote_service_template_path = get_remote_service_template_path(server_name, service_name);
|
||||||
std::string remote_script_path = remote_service_template_path + "/" + command + ".sh";
|
std::string remote_command_script_file = remote_service_template_path + "/" + command + ".sh";
|
||||||
std::string remote_service_env_file = get_remote_service_env_file(server_name, service_name);
|
std::string remote_service_config_path = get_remote_service_config_path(server_name, service_name);
|
||||||
if (!env.check_remote_items_exist({
|
if (!env.check_remote_items_exist({
|
||||||
get_remote_service_path(server_name, service_name),
|
get_remote_service_path(server_name, service_name),
|
||||||
remote_script_path,
|
remote_command_script_file,
|
||||||
remote_service_env_file})
|
get_remote_service_env_file(server_name, service_name)})
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
std::cerr << "Error: Required service directories not found on remote server" << std::endl;
|
std::cerr << "Error: Required service directories not found on remote server" << std::endl;
|
||||||
@ -150,7 +192,7 @@ int backup(const std::vector<std::string> & args) {
|
|||||||
|
|
||||||
// Create backups directory on server if it doesn't exist
|
// Create backups directory on server if it doesn't exist
|
||||||
std::string remote_backups_dir = get_remote_backups_path(server_name);
|
std::string remote_backups_dir = get_remote_backups_path(server_name);
|
||||||
std::cout << "Remote backups directory on "<< server_name <<": " << remote_backups_dir << std::endl;
|
if (!silent) std::cout << "Remote backups directory on "<< server_name <<": " << remote_backups_dir << std::endl;
|
||||||
std::string mkdir_cmd = "'mkdir -p " + quote(remote_backups_dir) + "'";
|
std::string mkdir_cmd = "'mkdir -p " + quote(remote_backups_dir) + "'";
|
||||||
if (!env.execute_ssh_command(mkdir_cmd, "Failed to create backups directory on server")) {
|
if (!env.execute_ssh_command(mkdir_cmd, "Failed to create backups directory on server")) {
|
||||||
return false;
|
return false;
|
||||||
@ -176,33 +218,32 @@ int backup(const std::vector<std::string> & args) {
|
|||||||
if (name_breaks_backups(service_info.template_name)) {std::cerr << "Error: Service template name contains invalid character sequence ( -_- ) that would break backup naming scheme" << std::endl; return 1;}
|
if (name_breaks_backups(service_info.template_name)) {std::cerr << "Error: Service template name contains invalid character sequence ( -_- ) that would break backup naming scheme" << std::endl; return 1;}
|
||||||
|
|
||||||
// Construct backup filename
|
// Construct backup filename
|
||||||
std::string backup_filename = server_name + "-_-" + service_info.template_name + "-_-" + service_name + "-_-" + datetime.str() + ".tgz";
|
std::string backup_filename = server_name + magic_string + service_info.template_name + magic_string + service_name + magic_string + datetime.str() + ".tgz";
|
||||||
std::string remote_backup_file_path = remote_backups_dir + "/" + backup_filename;
|
std::string remote_backup_file_path = remote_backups_dir + "/" + backup_filename;
|
||||||
std::string local_backup_file_path = (std::filesystem::path(local_backups_dir) / backup_filename).string();
|
std::string local_backup_file_path = (std::filesystem::path(local_backups_dir) / backup_filename).string();
|
||||||
|
|
||||||
// assert that the backup filename is valid - -_- appears exactly 3 times in local_backup_file_path.
|
// assert that the backup filename is valid - -_- appears exactly 3 times in local_backup_file_path.
|
||||||
ASSERT(3 == count_substring("-_-", local_backup_file_path));
|
ASSERT(3 == count_substring(magic_string, local_backup_file_path));
|
||||||
|
|
||||||
// Run backup script
|
// Run backup script
|
||||||
std::string backup_cmd = "'cd " + quote(remote_service_template_path) +
|
std::string backup_cmd = "'cd " + quote(remote_service_template_path) +
|
||||||
" && /bin/bash "+quote(remote_script_path)+" "+quote(remote_service_env_file)+" "+
|
" && /bin/bash "+quote(remote_command_script_file)+" "+quote(remote_service_config_path)+" "+
|
||||||
quote(remote_backup_file_path)+"'";
|
quote(remote_backup_file_path)+"'"+ (silent ? " > /dev/null 2>&1" : "");
|
||||||
|
|
||||||
if (!env.execute_ssh_command(backup_cmd, "Backup script failed")) {
|
if (!env.execute_ssh_command(backup_cmd, "Backup script failed")) {
|
||||||
std::cerr << "Backup script failed: " << backup_cmd << std::endl;
|
std::cerr << "Backup script failed: " << backup_cmd << std::endl;
|
||||||
return false;
|
return false;
|
||||||
} std::cout << "Remote backups directory on "<< server_name <<": " << get_remote_backups_path(server_name) << std::endl;
|
}
|
||||||
|
|
||||||
|
|
||||||
// Copy backup file from server to local
|
// Copy backup file from server to local
|
||||||
std::string scp_cmd = "scp -P " + env.get_SSH_PORT() + " " +
|
std::string scp_cmd = "scp -P " + env.get_SSH_PORT() + " " +
|
||||||
env.get_SSH_USER() + "@" + env.get_SSH_HOST() + ":" +
|
env.get_SSH_USER() + "@" + env.get_SSH_HOST() + ":" +
|
||||||
quote(remote_backup_file_path) + " " + quote(local_backup_file_path);
|
quote(remote_backup_file_path) + " " + quote(local_backup_file_path) + (silent ? " > /dev/null 2>&1" : "");
|
||||||
if (!env.execute_local_command(scp_cmd, "Failed to copy backup file from server")) {
|
if (!env.execute_local_command(scp_cmd, "Failed to copy backup file from server")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Backup created successfully: " << local_backup_file_path << std::endl;
|
if (!silent) std::cout << "Backup created successfully: " << local_backup_file_path << std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ namespace dropshell {
|
|||||||
|
|
||||||
int init(const std::vector<std::string> &args);
|
int init(const std::vector<std::string> &args);
|
||||||
int restore(const std::vector<std::string> &args);
|
int restore(const std::vector<std::string> &args);
|
||||||
int backup(const std::vector<std::string> &args);
|
int backup(const std::vector<std::string> &args, bool silent=false);
|
||||||
} // namespace main_commands
|
} // namespace main_commands
|
||||||
|
|
||||||
} // namespace dropshell
|
} // namespace dropshell
|
||||||
|
@ -247,4 +247,20 @@ int count_substring(const std::string &substring, const std::string &text) {
|
|||||||
return positions.size();
|
return positions.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> split(const std::string& str, const std::string& delimiter) {
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
size_t start = 0;
|
||||||
|
size_t end = 0;
|
||||||
|
|
||||||
|
while ((end = str.find(delimiter, start)) != std::string::npos) {
|
||||||
|
tokens.push_back(str.substr(start, end - start));
|
||||||
|
start = end + delimiter.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the last token
|
||||||
|
tokens.push_back(str.substr(start));
|
||||||
|
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dropshell
|
} // namespace dropshell
|
@ -21,6 +21,7 @@ std::string dequote(std::string str);
|
|||||||
std::string quote(std::string str);
|
std::string quote(std::string str);
|
||||||
std::string multi2string(std::vector<std::string> values);
|
std::string multi2string(std::vector<std::string> values);
|
||||||
std::vector<std::string> string2multi(std::string values);
|
std::vector<std::string> string2multi(std::string values);
|
||||||
|
std::vector<std::string> split(const std::string& str, const std::string& delimiter);
|
||||||
|
|
||||||
int str2int(const std::string & str);
|
int str2int(const std::string & str);
|
||||||
|
|
||||||
|
@ -37,10 +37,10 @@ load_env() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
env_file="$1/service.env"
|
env_file="$1"
|
||||||
|
|
||||||
if [ ! -f "$env_file" ]; then
|
if [ ! -f "$env_file" ]; then
|
||||||
echo "Warning: service.env file not found at $1/service.env"
|
echo "Warning: service.env file not found at $1"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user