main
 1{den, ...}: {
 2  den.quirks.backup.description = ''
 3    Restic backup entries collected from aspects (host)
 4
 5    Each aspect contributes a name -> services.restic.backups options map:
 6      backup = {
 7        foo = {
 8          paths = ["/var/lib/foo"];
 9          backupPrepareCommand = "…";
10        };
11      };
12
13    Names must be unique across aspects.
14  '';
15
16  den.aspects.core.includes = [den.aspects.core.backups];
17  den.aspects.core.backups = {
18    nixos = {
19      host,
20      backup,
21      lib,
22      config,
23      ...
24    }: let
25      mergeBackups = backups:
26        lib.foldl' (
27          acc: entry: let
28            duplicates = lib.intersectAttrs entry acc;
29          in
30            if duplicates != {}
31            then
32              throw ("core.backups: duplicate backup names collected from aspects:"
33                + "${lib.concatStringsSep ", " (lib.attrNames duplicates)}")
34            else acc // entry
35        ) {}
36        backups;
37
38      allBackups = mergeBackups backup;
39    in
40      lib.mkIf (allBackups != {}) {
41        services.restic.backups = lib.mapAttrs (name: value:
42          {
43            user = "root";
44            repository = "s3:https://584bf08b6f2fa0a8918cae5af0ee45bc.r2.cloudflarestorage.com/backups/${host.name}/${name}";
45            initialize = true;
46            environmentFile = config.vaultix.templates.restic-backup-env.path;
47            passwordFile = config.vaultix.secrets.restic-backup-password.path;
48            timerConfig = {
49              OnCalendar = "04:00";
50              RandomizedDelaySec = "1h";
51              Persistent = true;
52            };
53            pruneOpts = [
54              "--keep-daily 7"
55              "--keep-weekly 4"
56              "--keep-monthly 3"
57            ];
58          }
59          // value)
60        allBackups;
61
62        vaultix.secrets = {
63          restic-backup-r2-id.file = ./r2-id.age;
64          restic-backup-r2-key.file = ./r2-key.age;
65          restic-backup-password.file = ./password.age;
66        };
67
68        vaultix.templates.restic-backup-env.content = ''
69          AWS_ACCESS_KEY_ID=${config.vaultix.placeholder.restic-backup-r2-id}
70          AWS_SECRET_ACCESS_KEY=${config.vaultix.placeholder.restic-backup-r2-key}
71        '';
72      };
73  };
74}