|
|
|
@ -16,6 +16,10 @@ namespace dropshell {
|
|
|
|
|
|
|
|
|
|
namespace main_commands {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const std::string magic_string = "-_-";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int init(const std::vector<std::string> &args)
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
if (args.size() < 3) {
|
|
|
|
|
std::cerr << "Error: restore command requires a directory argument" << std::endl;
|
|
|
|
|
if (args.size() < 4) {
|
|
|
|
|
std::cerr << "Error: not enough arguments. dropshell restore <server> <service> <backup-file>" << std::endl;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -67,30 +71,63 @@ int restore(const std::vector<std::string> &args)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! std::filesystem::exists(backup_file)) {
|
|
|
|
|
std::cerr << "Error: Backup file not found" << std::endl;
|
|
|
|
|
std::string local_backups_dir = get_local_backup_path();
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
// backup_file is in format: server_name-template_name-service_name-YYYY-MM-DD_HH-MM-SS.tgz
|
|
|
|
|
// count '-' in backup_file
|
|
|
|
|
int dash_count = std::count(backup_file.begin(), backup_file.end(), '-');
|
|
|
|
|
if (dash_count != 3) {
|
|
|
|
|
|
|
|
|
|
// split the backup filename into parts based on the magic string
|
|
|
|
|
std::vector<std::string> parts = dropshell::split(backup_file, magic_string);
|
|
|
|
|
if (parts.size() != 4) {
|
|
|
|
|
std::cerr << "Error: Backup file format is incompatible, - in one of the names?" << std::endl;
|
|
|
|
|
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) {
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// run the restore script
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -110,7 +147,12 @@ bool name_breaks_backups(std::string name)
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
|
// 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 service_name = args[3];
|
|
|
|
|
|
|
|
|
@ -126,7 +168,7 @@ int backup(const std::vector<std::string> & args) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string command = "backup";
|
|
|
|
|
const std::string command = "backup";
|
|
|
|
|
|
|
|
|
|
if (!template_command_exists(service_info.template_name, command)) {
|
|
|
|
|
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.
|
|
|
|
|
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_service_env_file = get_remote_service_env_file(server_name, service_name);
|
|
|
|
|
std::string remote_command_script_file = remote_service_template_path + "/" + command + ".sh";
|
|
|
|
|
std::string remote_service_config_path = get_remote_service_config_path(server_name, service_name);
|
|
|
|
|
if (!env.check_remote_items_exist({
|
|
|
|
|
get_remote_service_path(server_name, service_name),
|
|
|
|
|
remote_script_path,
|
|
|
|
|
remote_service_env_file})
|
|
|
|
|
remote_command_script_file,
|
|
|
|
|
get_remote_service_env_file(server_name, service_name)})
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
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) + "'";
|
|
|
|
|
if (!env.execute_ssh_command(mkdir_cmd, "Failed to create backups directory on server")) {
|
|
|
|
|
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;}
|
|
|
|
|
|
|
|
|
|
// 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 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(3 == count_substring("-_-", local_backup_file_path));
|
|
|
|
|
ASSERT(3 == count_substring(magic_string, local_backup_file_path));
|
|
|
|
|
|
|
|
|
|
// Run backup script
|
|
|
|
|
std::string backup_cmd = "'cd " + quote(remote_service_template_path) +
|
|
|
|
|
" && /bin/bash "+quote(remote_script_path)+" "+quote(remote_service_env_file)+" "+
|
|
|
|
|
quote(remote_backup_file_path)+"'";
|
|
|
|
|
" && /bin/bash "+quote(remote_command_script_file)+" "+quote(remote_service_config_path)+" "+
|
|
|
|
|
quote(remote_backup_file_path)+"'"+ (silent ? " > /dev/null 2>&1" : "");
|
|
|
|
|
|
|
|
|
|
if (!env.execute_ssh_command(backup_cmd, "Backup script failed")) {
|
|
|
|
|
std::cerr << "Backup script failed: " << backup_cmd << std::endl;
|
|
|
|
|
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
|
|
|
|
|
std::string scp_cmd = "scp -P " + env.get_SSH_PORT() + " " +
|
|
|
|
|
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")) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|