Merge pull request 'backup fixes' (#2650) from borgbackup into main
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
(import ../lib/container-test.nix) (
|
(import ../lib/container-test.nix) (
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
name = "secrets";
|
name = "deltachat";
|
||||||
|
|
||||||
nodes.machine =
|
nodes.machine =
|
||||||
{ self, ... }:
|
{ self, ... }:
|
||||||
|
|||||||
@@ -138,34 +138,43 @@ in
|
|||||||
}) cfg.destinations;
|
}) cfg.destinations;
|
||||||
|
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
(pkgs.writeShellScriptBin "borgbackup-create" ''
|
(pkgs.writeShellApplication {
|
||||||
set -efu -o pipefail
|
name = "borgbackup-create";
|
||||||
${lib.concatMapStringsSep "\n" (dest: ''
|
runtimeInputs = [ config.systemd.package ];
|
||||||
systemctl start borgbackup-job-${dest.name}
|
text = ''
|
||||||
'') (lib.attrValues cfg.destinations)}
|
${lib.concatMapStringsSep "\n" (dest: ''
|
||||||
'')
|
systemctl start borgbackup-job-${dest.name}
|
||||||
(pkgs.writeShellScriptBin "borgbackup-list" ''
|
'') (lib.attrValues cfg.destinations)}
|
||||||
set -efu
|
'';
|
||||||
(${
|
})
|
||||||
lib.concatMapStringsSep "\n" (
|
(pkgs.writeShellApplication {
|
||||||
dest:
|
name = "borgbackup-list";
|
||||||
# we need yes here to skip the changed url verification
|
runtimeInputs = [ pkgs.jq ];
|
||||||
''yes y | borg-job-${dest.name} list --json | jq '[.archives[] | {"name": ("${dest.name}::${dest.repo}::" + .name)}]' ''
|
text = ''
|
||||||
) (lib.attrValues cfg.destinations)
|
(${
|
||||||
}) | ${pkgs.jq}/bin/jq -s 'add'
|
lib.concatMapStringsSep "\n" (
|
||||||
'')
|
dest:
|
||||||
(pkgs.writeShellScriptBin "borgbackup-restore" ''
|
# we need yes here to skip the changed url verification
|
||||||
set -efux
|
''echo y | /run/current-system/sw/bin/borg-job-${dest.name} list --json | jq '[.archives[] | {"name": ("${dest.name}::${dest.repo}::" + .name)}]' ''
|
||||||
cd /
|
) (lib.attrValues cfg.destinations)
|
||||||
IFS=':' read -ra FOLDER <<< "$FOLDERS"
|
}) | jq -s 'add // []'
|
||||||
job_name=$(echo "$NAME" | ${pkgs.gawk}/bin/awk -F'::' '{print $1}')
|
'';
|
||||||
backup_name=''${NAME#"$job_name"::}
|
})
|
||||||
if ! command -v borg-job-"$job_name" &> /dev/null; then
|
(pkgs.writeShellApplication {
|
||||||
echo "borg-job-$job_name not found: Backup name is invalid" >&2
|
name = "borgbackup-restore";
|
||||||
exit 1
|
runtimeInputs = [ pkgs.gawk ];
|
||||||
fi
|
text = ''
|
||||||
yes y | borg-job-"$job_name" extract --list "$backup_name" "''${FOLDER[@]}"
|
cd /
|
||||||
'')
|
IFS=':' read -ra FOLDER <<< "''${FOLDERS-}"
|
||||||
|
job_name=$(echo "$NAME" | awk -F'::' '{print $1}')
|
||||||
|
backup_name=''${NAME#"$job_name"::}
|
||||||
|
if [[ ! -x /run/current-system/sw/bin/borg-job-"$job_name" ]]; then
|
||||||
|
echo "borg-job-$job_name not found: Backup name is invalid" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo y | /run/current-system/sw/bin/borg-job-"$job_name" extract "$backup_name" "''${FOLDER[@]}"
|
||||||
|
'';
|
||||||
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
# Facts generation. So the client can authenticate to the server
|
# Facts generation. So the client can authenticate to the server
|
||||||
|
|||||||
@@ -21,15 +21,25 @@ class Backup:
|
|||||||
def list_provider(machine: Machine, provider: str) -> list[Backup]:
|
def list_provider(machine: Machine, provider: str) -> list[Backup]:
|
||||||
results = []
|
results = []
|
||||||
backup_metadata = json.loads(machine.eval_nix("config.clan.core.backups"))
|
backup_metadata = json.loads(machine.eval_nix("config.clan.core.backups"))
|
||||||
|
list_command = backup_metadata["providers"][provider]["list"]
|
||||||
proc = machine.target_host.run(
|
proc = machine.target_host.run(
|
||||||
[backup_metadata["providers"][provider]["list"]],
|
[list_command],
|
||||||
RunOpts(log=Log.STDERR, check=False),
|
RunOpts(log=Log.NONE, check=False),
|
||||||
)
|
)
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
# TODO this should be a warning, only raise exception if no providers succeed
|
# TODO this should be a warning, only raise exception if no providers succeed
|
||||||
msg = f"failed to list backups for provider {provider}: {proc.stdout}"
|
msg = f"Failed to list backups for provider {provider}:"
|
||||||
|
msg += f"\n{list_command} exited with {proc.returncode}"
|
||||||
|
if proc.stderr:
|
||||||
|
msg += f"\nerror output: {proc.stderr}"
|
||||||
raise ClanError(msg)
|
raise ClanError(msg)
|
||||||
parsed_json = json.loads(proc.stdout)
|
|
||||||
|
try:
|
||||||
|
parsed_json = json.loads(proc.stdout)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
msg = f"Failed to parse json output from provider {provider}:\n{proc.stdout}"
|
||||||
|
raise ClanError(msg) from e
|
||||||
|
|
||||||
for archive in parsed_json:
|
for archive in parsed_json:
|
||||||
results.append(Backup(name=archive["name"], job_name=archive.get("job_name")))
|
results.append(Backup(name=archive["name"], job_name=archive.get("job_name")))
|
||||||
return results
|
return results
|
||||||
|
|||||||
Reference in New Issue
Block a user