forked from clan/clan-core
Merge pull request 'backups: implement list the easy way' (#614) from lassulus-backups2 into main
This commit is contained in:
commit
7f68da2715
@ -1,4 +1,4 @@
|
|||||||
{ config, lib, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.clan.borgbackup;
|
cfg = config.clan.borgbackup;
|
||||||
in
|
in
|
||||||
@ -19,7 +19,7 @@ in
|
|||||||
};
|
};
|
||||||
rsh = lib.mkOption {
|
rsh = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "";
|
default = "ssh -i ${config.clanCore.secrets.borgbackup.secrets."borgbackup.ssh".path} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null";
|
||||||
description = "the rsh to use for the backup";
|
description = "the rsh to use for the backup";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -55,15 +55,23 @@ in
|
|||||||
})
|
})
|
||||||
cfg.destinations;
|
cfg.destinations;
|
||||||
|
|
||||||
|
clanCore.secrets.borgbackup = {
|
||||||
|
facts."borgbackup.ssh.pub" = { };
|
||||||
|
secrets."borgbackup.ssh" = { };
|
||||||
|
generator.path = [ pkgs.openssh pkgs.coreutils ];
|
||||||
|
generator.script = ''
|
||||||
|
ssh-keygen -t ed25519 -N "" -f "$secrets"/borgbackup.ssh
|
||||||
|
mv "$secrets"/borgbackup.ssh.pub "$facts"/borgbackup.ssh.pub
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
clanCore.backups.providers.borgbackup = {
|
clanCore.backups.providers.borgbackup = {
|
||||||
list = ''
|
list = ''
|
||||||
${lib.concatMapStringsSep "\n" (dest: ''
|
ssh ${config.clan.networking.deploymentAddress} -- '
|
||||||
(
|
${lib.concatMapStringsSep "\n" (dest: ''
|
||||||
export BORG_REPO=${lib.escapeShellArg dest.repo}
|
borg-job-${dest.name} list --json
|
||||||
export BORG_RSH=${lib.escapeShellArg dest.rsh}
|
'') (lib.attrValues cfg.destinations)}
|
||||||
${lib.getExe config.services.borgbackup.package} list
|
'
|
||||||
)
|
|
||||||
'') (lib.attrValues cfg.destinations)}
|
|
||||||
'';
|
'';
|
||||||
start = ''
|
start = ''
|
||||||
ssh ${config.clan.networking.deploymentAddress} -- '
|
ssh ${config.clan.networking.deploymentAddress} -- '
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
default = [ ];
|
default = { };
|
||||||
description = ''
|
description = ''
|
||||||
Configured backup providers which are used by this machine
|
Configured backup providers which are used by this machine
|
||||||
'';
|
'';
|
||||||
|
@ -1,57 +1,47 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import pprint
|
import json
|
||||||
from pathlib import Path
|
import subprocess
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from ..errors import ClanError
|
from ..errors import ClanError
|
||||||
|
from ..machines.machines import Machine
|
||||||
|
|
||||||
|
|
||||||
def list_backups(
|
def list_backups(machine: Machine, provider: str | None = None) -> list[dict[str, Any]]:
|
||||||
flake_dir: Path, machine: str, provider: str | None = None
|
backup_scripts = json.loads(
|
||||||
) -> dict[str, dict[str, list[dict[str, str]]]]:
|
machine.eval_nix(f"nixosConfigurations.{machine.name}.config.clanCore.backups")
|
||||||
dummy_data = {
|
)
|
||||||
"testhostname": {
|
results = []
|
||||||
"borgbackup": [
|
if provider is None:
|
||||||
{"date": "2021-01-01T00:00:00Z", "id": "1"},
|
for provider in backup_scripts["providers"]:
|
||||||
{"date": "2022-01-01T00:00:00Z", "id": "2"},
|
proc = subprocess.run(
|
||||||
{"date": "2023-01-01T00:00:00Z", "id": "3"},
|
["bash", "-c", backup_scripts["providers"][provider]["list"]],
|
||||||
],
|
stdout=subprocess.PIPE,
|
||||||
"restic": [
|
)
|
||||||
{"date": "2021-01-01T00:00:00Z", "id": "1"},
|
if proc.returncode != 0:
|
||||||
{"date": "2022-01-01T00:00:00Z", "id": "2"},
|
# TODO this should be a warning, only raise exception if no providers succeed
|
||||||
{"date": "2023-01-01T00:00:00Z", "id": "3"},
|
raise ClanError("failed to list backups")
|
||||||
],
|
else:
|
||||||
},
|
results.append(proc.stdout)
|
||||||
"another host": {
|
|
||||||
"borgbackup": [
|
|
||||||
{"date": "2021-01-01T00:00:00Z", "id": "1"},
|
|
||||||
{"date": "2022-01-01T00:00:00Z", "id": "2"},
|
|
||||||
{"date": "2023-01-01T00:00:00Z", "id": "3"},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if provider is not None:
|
|
||||||
new_data = {}
|
|
||||||
for machine_ in dummy_data:
|
|
||||||
if provider in dummy_data[machine_]:
|
|
||||||
new_data[machine_] = {provider: dummy_data[machine_][provider]}
|
|
||||||
dummy_data = new_data
|
|
||||||
|
|
||||||
if machine is None:
|
|
||||||
return dummy_data
|
|
||||||
else:
|
else:
|
||||||
return {machine: dummy_data[machine]}
|
if provider not in backup_scripts["providers"]:
|
||||||
|
raise ClanError(f"provider {provider} not found")
|
||||||
|
proc = subprocess.run(
|
||||||
|
["bash", "-c", backup_scripts["providers"][provider]["list"]],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
raise ClanError("failed to list backup")
|
||||||
|
else:
|
||||||
|
results.append(proc.stdout)
|
||||||
|
|
||||||
|
return list(map(json.loads, results))
|
||||||
|
|
||||||
|
|
||||||
def list_command(args: argparse.Namespace) -> None:
|
def list_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")
|
backups_data = list_backups(machine=machine, provider=args.provider)
|
||||||
backups = list_backups(
|
print(list(backups_data))
|
||||||
Path(args.flake), machine=args.machine, provider=args.provider
|
|
||||||
)
|
|
||||||
if len(backups) > 0:
|
|
||||||
pp = pprint.PrettyPrinter(depth=4)
|
|
||||||
pp.pprint(backups)
|
|
||||||
|
|
||||||
|
|
||||||
def register_list_parser(parser: argparse.ArgumentParser) -> None:
|
def register_list_parser(parser: argparse.ArgumentParser) -> None:
|
||||||
|
@ -1,22 +1,20 @@
|
|||||||
import logging
|
import pytest
|
||||||
|
|
||||||
from cli import Cli
|
from cli import Cli
|
||||||
from fixtures_flakes import FlakeForTest
|
from fixtures_flakes import FlakeForTest
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.impure
|
||||||
def test_backups(
|
def test_backups(
|
||||||
test_flake: FlakeForTest,
|
test_flake_with_core: FlakeForTest,
|
||||||
) -> None:
|
) -> None:
|
||||||
cli = Cli()
|
cli = Cli()
|
||||||
|
|
||||||
cli.run(
|
cli.run(
|
||||||
[
|
[
|
||||||
"--flake",
|
"--flake",
|
||||||
str(test_flake.path),
|
str(test_flake_with_core.path),
|
||||||
"backups",
|
"backups",
|
||||||
"list",
|
"list",
|
||||||
"testhostname",
|
"vm1",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user