Merge pull request 'backups: implement list the easy way' (#617) from lassulus-backups2 into main
This commit is contained in:
@@ -67,11 +67,11 @@ in
|
|||||||
|
|
||||||
clanCore.backups.providers.borgbackup = {
|
clanCore.backups.providers.borgbackup = {
|
||||||
list = ''
|
list = ''
|
||||||
ssh ${config.clan.networking.deploymentAddress} -- '
|
ssh ${config.clan.networking.deploymentAddress} <<EOF
|
||||||
${lib.concatMapStringsSep "\n" (dest: ''
|
${lib.concatMapStringsSep "\n" (dest: ''
|
||||||
borg-job-${dest.name} list --json
|
borg-job-${dest.name} list --json | jq -r '. + {"job-name": "${dest.name}"}'
|
||||||
'') (lib.attrValues cfg.destinations)}
|
'') (lib.attrValues cfg.destinations)}
|
||||||
'
|
EOF
|
||||||
'';
|
'';
|
||||||
start = ''
|
start = ''
|
||||||
ssh ${config.clan.networking.deploymentAddress} -- '
|
ssh ${config.clan.networking.deploymentAddress} -- '
|
||||||
@@ -82,6 +82,11 @@ in
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
restore = ''
|
restore = ''
|
||||||
|
ssh ${config.clan.networking.deploymentAddress} -- LOCATION="$LOCATION" ARCHIVE="$ARCHIVE_ID" JOB="$JOB" '
|
||||||
|
set -efux
|
||||||
|
cd /
|
||||||
|
borg-job-"$JOB" extract --list --dry-run "$LOCATION"::"$ARCHIVE"
|
||||||
|
'
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,13 +11,19 @@
|
|||||||
Folder where state resides in
|
Folder where state resides in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
restoreScript = lib.mkOption {
|
preRestoreScript = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = ":";
|
||||||
|
description = ''
|
||||||
|
script to run before restoring the state dir from a backup
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
postRestoreScript = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = ":";
|
default = ":";
|
||||||
description = ''
|
description = ''
|
||||||
script to restore the service after the state dir was restored from a backup
|
script to restore the service after the state dir was restored from a backup
|
||||||
'';
|
'';
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ def list_backups(machine: Machine, provider: str | None = None) -> list[dict[str
|
|||||||
def list_command(args: argparse.Namespace) -> None:
|
def list_command(args: argparse.Namespace) -> None:
|
||||||
machine = Machine(name=args.machine, flake_dir=args.flake)
|
machine = Machine(name=args.machine, flake_dir=args.flake)
|
||||||
backups_data = list_backups(machine=machine, provider=args.provider)
|
backups_data = list_backups(machine=machine, provider=args.provider)
|
||||||
print(list(backups_data))
|
print(json.dumps(list(backups_data)))
|
||||||
|
|
||||||
|
|
||||||
def register_list_parser(parser: argparse.ArgumentParser) -> None:
|
def register_list_parser(parser: argparse.ArgumentParser) -> None:
|
||||||
|
|||||||
@@ -1,32 +1,67 @@
|
|||||||
import argparse
|
import argparse
|
||||||
from pathlib import Path
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from ..errors import ClanError
|
from ..errors import ClanError
|
||||||
|
from ..machines.machines import Machine
|
||||||
|
from .list import list_backups
|
||||||
|
|
||||||
|
|
||||||
def restore_backup(
|
def restore_backup(
|
||||||
flake_dir: Path,
|
backup_data: list[dict[str, Any]],
|
||||||
machine: str,
|
machine: Machine,
|
||||||
provider: str,
|
provider: str,
|
||||||
backup_id: str,
|
archive_id: str,
|
||||||
service: str | None = None,
|
service: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
backup_scripts = json.loads(
|
||||||
|
machine.eval_nix(f"nixosConfigurations.{machine.name}.config.clanCore.backups")
|
||||||
|
)
|
||||||
|
backup_folders = json.loads(
|
||||||
|
machine.eval_nix(f"nixosConfigurations.{machine.name}.config.clanCore.state")
|
||||||
|
)
|
||||||
if service is None:
|
if service is None:
|
||||||
print("would restore backup", machine, provider, backup_id)
|
for backup in backup_data:
|
||||||
|
for archive in backup["archives"]:
|
||||||
|
if archive["archive"] == archive_id:
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["ARCHIVE_ID"] = archive_id
|
||||||
|
env["LOCATION"] = backup["repository"]["location"]
|
||||||
|
env["JOB"] = backup["job-name"]
|
||||||
|
proc = subprocess.run(
|
||||||
|
[
|
||||||
|
"bash",
|
||||||
|
"-c",
|
||||||
|
backup_scripts["providers"][provider]["restore"],
|
||||||
|
],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
env=env,
|
||||||
|
)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
# TODO this should be a warning, only raise exception if no providers succeed
|
||||||
|
raise ClanError("failed to restore backup")
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
"would restore backup", machine, provider, backup_id, "of service:", service
|
"would restore backup",
|
||||||
|
machine,
|
||||||
|
provider,
|
||||||
|
archive_id,
|
||||||
|
"of service:",
|
||||||
|
service,
|
||||||
)
|
)
|
||||||
|
print(backup_folders)
|
||||||
|
|
||||||
|
|
||||||
def restore_command(args: argparse.Namespace) -> None:
|
def restore_command(args: argparse.Namespace) -> None:
|
||||||
if args.flake is None:
|
machine = Machine(name=args.machine, flake_dir=args.flake)
|
||||||
raise ClanError("Could not find clan flake toplevel directory")
|
backup_data = list_backups(machine=machine, provider=args.provider)
|
||||||
restore_backup(
|
restore_backup(
|
||||||
Path(args.flake),
|
backup_data=backup_data,
|
||||||
machine=args.machine,
|
machine=machine,
|
||||||
provider=args.provider,
|
provider=args.provider,
|
||||||
backup_id=args.backup_id,
|
archive_id=args.archive_id,
|
||||||
service=args.service,
|
service=args.service,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -36,6 +71,6 @@ def register_restore_parser(parser: argparse.ArgumentParser) -> None:
|
|||||||
"machine", type=str, help="machine in the flake to create backups of"
|
"machine", type=str, help="machine in the flake to create backups of"
|
||||||
)
|
)
|
||||||
parser.add_argument("provider", type=str, help="backup provider to use")
|
parser.add_argument("provider", type=str, help="backup provider to use")
|
||||||
parser.add_argument("backup_id", type=str, help="id of the backup to restore")
|
parser.add_argument("archive_id", type=str, help="id of the backup to restore")
|
||||||
parser.add_argument("--service", type=str, help="name of the service to restore")
|
parser.add_argument("--service", type=str, help="name of the service to restore")
|
||||||
parser.set_defaults(func=restore_command)
|
parser.set_defaults(func=restore_command)
|
||||||
|
|||||||
Reference in New Issue
Block a user