From 7e6021d2ab79123b731422994156f4c58dc61c24 Mon Sep 17 00:00:00 2001 From: Wojciech Kozlowski Date: Sat, 30 Sep 2023 23:43:27 +0200 Subject: [PATCH] Add option to restore using syncoid --- .../snapshots/setup/files/syncoid-batch | 89 ++++++++++++------- .../setup/templates/syncoid-batch.service | 2 +- 2 files changed, 57 insertions(+), 34 deletions(-) diff --git a/playbooks/roles/backups/snapshots/setup/files/syncoid-batch b/playbooks/roles/backups/snapshots/setup/files/syncoid-batch index 060df2c..af082ab 100644 --- a/playbooks/roles/backups/snapshots/setup/files/syncoid-batch +++ b/playbooks/roles/backups/snapshots/setup/files/syncoid-batch @@ -6,50 +6,73 @@ import subprocess import yaml -def load_and_validate_config_dir(config_dir): - if not os.path.isdir(config_dir): - raise ValueError(f"{config_dir} is not a directory") +class BatchManager: - return [ - load_and_validate_config_file(os.path.join(config_dir, file)) - for file in os.listdir(config_dir) - ] + def __init__(self, config_dir): + self.__config_list = BatchManager.__load_and_validate_config_dir(config_dir) + + @staticmethod + def __load_and_validate_config_dir(config_dir): + if not os.path.isdir(config_dir): + raise ValueError(f"{config_dir} is not a directory") + + return [ + BatchManager.__load_and_validate_config_file(os.path.join(config_dir, file)) + for file in os.listdir(config_dir) + ] -def load_and_validate_config_file(config_file_path): - if not os.path.isfile(config_file_path): - raise ValueError(f"{config_file_path} is not a file") + @staticmethod + def __load_and_validate_config_file(config_file_path): + if not os.path.isfile(config_file_path): + raise ValueError(f"{config_file_path} is not a file") - with open(config_file_path, encoding="utf-8") as config_file: - config = yaml.safe_load(config_file) + with open(config_file_path, encoding="utf-8") as config_file: + config = yaml.safe_load(config_file) - for key in ["dataset", "backup_dataset"]: - if key not in config: - raise KeyError(f"{key} must be present in {config_file_path}") + for key in ["dataset", "backup_dataset"]: + if key not in config: + raise KeyError(f"{key} must be present in {config_file_path}") - return config + return config + + def __exec(self, source_key, destination_key): + for config in self.__config_list: + syncoid_cmd = ["/usr/sbin/syncoid", "--no-sync-snap", "--preserve-properties"] + if config.get("recursive", False): + syncoid_cmd.append("--recursive") + if config.get("skip_parent", False): + syncoid_cmd.append("--skip-parent") + syncoid_cmd.append(config[source_key]) + syncoid_cmd.append(config[destination_key]) + + try: + subprocess.run(syncoid_cmd, check=True, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as err: + print(err.stdout.decode("ascii"), flush=True) + raise + + def backup(self): + self.__exec("dataset", "backup_dataset") + + def restore(self): + self.__exec("backup_dataset", "dataset") if __name__ == "__main__": parser = argparse.ArgumentParser(description="Backup service data using syncoid") parser.add_argument("--config-dir", type=str, default="/etc/syncoid-batch.d", help="Path to directory with YAML config files") + + subparsers = parser.add_subparsers() + + backup_parser = subparsers.add_parser("backup") + backup_parser.set_defaults(func=BatchManager.backup) + + restore_parser = subparsers.add_parser("restore") + restore_parser.set_defaults(func=BatchManager.restore) + args = parser.parse_args() - config_list = load_and_validate_config_dir(args.config_dir) - - for config in config_list: - syncoid_cmd = ["/usr/sbin/syncoid", "--no-sync-snap"] - if config.get("recursive", False): - syncoid_cmd.append("--recursive") - if config.get("skip_parent", False): - syncoid_cmd.append("--skip-parent") - syncoid_cmd.append(config["dataset"]) - syncoid_cmd.append(config["backup_dataset"]) - - try: - subprocess.run(syncoid_cmd, check=True, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as err: - print(err.stdout.decode("ascii"), flush=True) - raise + args.func(BatchManager(args.config_dir)) diff --git a/playbooks/roles/backups/snapshots/setup/templates/syncoid-batch.service b/playbooks/roles/backups/snapshots/setup/templates/syncoid-batch.service index 7c93401..9b5176a 100644 --- a/playbooks/roles/backups/snapshots/setup/templates/syncoid-batch.service +++ b/playbooks/roles/backups/snapshots/setup/templates/syncoid-batch.service @@ -7,7 +7,7 @@ OnFailure=status-mail@%n.service [Service] Type=oneshot -ExecStart=/usr/local/sbin/syncoid-batch --config-dir {{ system_etc_root_directory }}/syncoid-batch.d +ExecStart=/usr/local/sbin/syncoid-batch --config-dir {{ system_etc_root_directory }}/syncoid-batch.d backup [Install] WantedBy=sanoid.service