From aa659bcc171df895d425723763e08913194e3bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Wed, 20 Mar 2024 07:28:02 +0100 Subject: [PATCH] backups: no longer interpret backup interface as bash commands --- checks/backups/flake-module.nix | 4 +-- clanModules/borgbackup.nix | 41 +++++++++++++---------- pkgs/clan-cli/clan_cli/backups/create.py | 4 +-- pkgs/clan-cli/clan_cli/backups/list.py | 2 +- pkgs/clan-cli/clan_cli/backups/restore.py | 18 ++-------- 5 files changed, 32 insertions(+), 37 deletions(-) diff --git a/checks/backups/flake-module.nix b/checks/backups/flake-module.nix index ac8317b8..485e625b 100644 --- a/checks/backups/flake-module.nix +++ b/checks/backups/flake-module.nix @@ -119,13 +119,13 @@ # list backup_id = json.loads(machine.succeed("borg-job-test-backup list --json"))["archives"][0]["archive"] - out = machine.succeed("clan --debug --flake ${self} backups list test-backup") + out = machine.succeed("clan --debug --flake ${self} backups list test-backup").strip() print(out) assert backup_id in out, f"backup {backup_id} not found in {out}" # restore machine.succeed("rm -f /var/test-backups/somefile") - machine.succeed(f"clan --debug --flake ${self} backups restore test-backup borgbackup borg@machine:.::{backup_id} >&2") + machine.succeed(f"clan --debug --flake ${self} backups restore test-backup borgbackup {out} >&2") assert machine.succeed("cat /var/test-backups/somefile").strip() == "testing", "restore failed" ''; } { inherit pkgs self; }; diff --git a/clanModules/borgbackup.nix b/clanModules/borgbackup.nix index 7b5ffb16..e2a413ed 100644 --- a/clanModules/borgbackup.nix +++ b/clanModules/borgbackup.nix @@ -90,11 +90,14 @@ in ''; }; - environment.systemPackages = [ pkgs.jq ]; - - clanCore.backups.providers.borgbackup = { - # TODO list needs to run locally or on the remote machine - list = '' + environment.systemPackages = [ + (pkgs.writeShellScriptBin "borgbackup-create" '' + set -efu -o pipefail + ${lib.concatMapStringsSep "\n" (dest: '' + systemctl start borgbackup-job-${dest.name} + '') (lib.attrValues cfg.destinations)} + '') + (pkgs.writeShellScriptBin "borgbackup-list" '' set -efu (${ lib.concatMapStringsSep "\n" ( @@ -102,21 +105,25 @@ in # we need yes here to skip the changed url verification ''yes y | borg-job-${dest.name} list --json | jq '[.archives[] | {"name": ("${dest.name}::${dest.repo}::" + .name)}]' '' ) (lib.attrValues cfg.destinations) - }) | jq -s 'add' - ''; - create = '' - ${lib.concatMapStringsSep "\n" (dest: '' - systemctl start borgbackup-job-${dest.name} - '') (lib.attrValues cfg.destinations)} - ''; - - restore = '' - set -efu + }) | ${pkgs.jq}/bin/jq -s 'add' + '') + (pkgs.writeShellScriptBin "borgbackup-restore" '' + set -efux cd / IFS=';' read -ra FOLDER <<< "$FOLDERS" - job_name=$(echo "$NAME" | cut -d'::' -f1) + job_name=$(echo "$NAME" | ${pkgs.gawk}/bin/awk -F'::' '{print $1}') + if ! command -v borg-job-"$job_name" &> /dev/null; then + echo "borg-job-$job_name not found: Backup name is invalid" >&2 + exit 1 + fi yes y | borg-job-"$job_name" extract --list "$NAME" "''${FOLDER[@]}" - ''; + '') + ]; + + clanCore.backups.providers.borgbackup = { + list = "borgbackup-list"; + create = "borgbackup-create"; + restore = "borgbackup-restore"; }; }; } diff --git a/pkgs/clan-cli/clan_cli/backups/create.py b/pkgs/clan-cli/clan_cli/backups/create.py index b8573794..e354346d 100644 --- a/pkgs/clan-cli/clan_cli/backups/create.py +++ b/pkgs/clan-cli/clan_cli/backups/create.py @@ -14,7 +14,7 @@ def create_backup(machine: Machine, provider: str | None = None) -> None: if provider is None: for provider in backup_scripts["providers"]: proc = machine.target_host.run( - ["bash", "-c", backup_scripts["providers"][provider]["create"]], + [backup_scripts["providers"][provider]["create"]], ) if proc.returncode != 0: raise ClanError("failed to start backup") @@ -24,7 +24,7 @@ def create_backup(machine: Machine, provider: str | None = None) -> None: if provider not in backup_scripts["providers"]: raise ClanError(f"provider {provider} not found") proc = machine.target_host.run( - ["bash", "-c", backup_scripts["providers"][provider]["create"]], + [backup_scripts["providers"][provider]["create"]], ) if proc.returncode != 0: raise ClanError("failed to start backup") diff --git a/pkgs/clan-cli/clan_cli/backups/list.py b/pkgs/clan-cli/clan_cli/backups/list.py index 272f50a4..e180481a 100644 --- a/pkgs/clan-cli/clan_cli/backups/list.py +++ b/pkgs/clan-cli/clan_cli/backups/list.py @@ -17,7 +17,7 @@ def list_provider(machine: Machine, provider: str) -> list[Backup]: results = [] backup_metadata = json.loads(machine.eval_nix("config.clanCore.backups")) proc = machine.target_host.run( - ["bash", "-c", backup_metadata["providers"][provider]["list"]], + [backup_metadata["providers"][provider]["list"]], stdout=subprocess.PIPE, check=False, ) diff --git a/pkgs/clan-cli/clan_cli/backups/restore.py b/pkgs/clan-cli/clan_cli/backups/restore.py index 4907acd7..e94aaf25 100644 --- a/pkgs/clan-cli/clan_cli/backups/restore.py +++ b/pkgs/clan-cli/clan_cli/backups/restore.py @@ -15,11 +15,7 @@ def restore_service(machine: Machine, name: str, provider: str, service: str) -> env["FOLDERS"] = ":".join(folders) proc = machine.target_host.run( - [ - "bash", - "-c", - backup_folders[service]["preRestoreScript"], - ], + [backup_folders[service]["preRestoreScript"]], stdout=subprocess.PIPE, extra_env=env, ) @@ -29,11 +25,7 @@ def restore_service(machine: Machine, name: str, provider: str, service: str) -> ) proc = machine.target_host.run( - [ - "bash", - "-c", - backup_metadata["providers"][provider]["restore"], - ], + [backup_metadata["providers"][provider]["restore"]], stdout=subprocess.PIPE, extra_env=env, ) @@ -43,11 +35,7 @@ def restore_service(machine: Machine, name: str, provider: str, service: str) -> ) proc = machine.target_host.run( - [ - "bash", - "-c", - backup_folders[service]["postRestoreScript"], - ], + [backup_folders[service]["postRestoreScript"]], stdout=subprocess.PIPE, extra_env=env, )