#!/usr/bin/env python3 import argparse import os import subprocess import yaml class BatchManager: 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) ] @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) for key in ["dataset", "backup_dataset"]: if key not in config: raise KeyError(f"{key} must be present in {config_file_path}") return config def __exec(self, source_key, destination_key): for config in self.__config_list: syncoid_cmd = ["/usr/sbin/syncoid", "--no-sync-snap", "--sendoptions=\"p\""] 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() args.func(BatchManager(args.config_dir))