diff --git a/modules/system/services/restic/backups.nix b/modules/system/services/restic/backups.nix index b640160..1e5a8e5 100644 --- a/modules/system/services/restic/backups.nix +++ b/modules/system/services/restic/backups.nix @@ -1,34 +1,42 @@ { config, lib, ... }: let - backups = config.custom.services.restic.backups |> lib.filterAttrs (_: backup: backup.enable); + backups = + config.custom.services.restic.backups |> lib.attrValues |> lib.filter (backup: backup.enable); in { options.custom.services.restic.backups = lib.mkOption { type = lib.types.attrsOf ( - lib.types.submodule { - options = { - enable = lib.mkEnableOption "" // { - default = true; + lib.types.submodule ( + { name, ... }: + { + options = { + enable = lib.mkEnableOption "" // { + default = true; + }; + name = lib.mkOption { + type = lib.types.nonEmptyStr; + default = name; + }; + conflictingService = lib.mkOption { + type = lib.types.nullOr lib.types.nonEmptyStr; + default = null; + }; + paths = lib.mkOption { + type = lib.types.listOf lib.types.path; + default = [ ]; + }; + extraConfig = lib.mkOption { + type = lib.types.attrsOf lib.types.anything; + default = { }; + }; }; - conflictingService = lib.mkOption { - type = lib.types.nullOr lib.types.nonEmptyStr; - default = null; - }; - paths = lib.mkOption { - type = lib.types.listOf lib.types.path; - default = [ ]; - }; - extraConfig = lib.mkOption { - type = lib.types.attrsOf lib.types.anything; - default = { }; - }; - }; - } + } + ) ); default = { }; }; - config = lib.mkIf (backups != { }) { + config = lib.mkIf (backups != [ ]) { sops = { secrets = { "backblaze/key-id" = { }; @@ -43,17 +51,17 @@ in }; systemd.tmpfiles.rules = - backups |> lib.attrNames |> lib.map (name: "d /var/cache/restic-backups-${name} 700 - - -"); + backups |> lib.map (backup: "d /var/cache/restic-backups-${backup.name} 700 - - -"); services.restic.backups = backups - |> lib.mapAttrs ( - name: backup: - lib.mkMerge [ + |> lib.map (backup: { + inherit (backup) name; + value = lib.mkMerge [ { inherit (backup) paths; initialize = true; - repository = "s3:https://s3.eu-central-003.backblazeb2.com/stork-atlas/${name}"; + repository = "s3:https://s3.eu-central-003.backblazeb2.com/stork-atlas/${backup.name}"; environmentFile = config.sops.templates."restic/environment".path; passwordFile = config.sops.secrets."restic/password".path; pruneOpts = [ @@ -67,21 +75,22 @@ in }; } backup.extraConfig - ] - ); + ]; + }) + |> lib.listToAttrs; systemd.services = backups - |> lib.mapAttrs' ( - name: backup: - lib.nameValuePair "restic-backups-${name}" ( - lib.mkIf (backup.conflictingService != null) { - unitConfig.Conflicts = [ backup.conflictingService ]; - after = [ backup.conflictingService ]; - onSuccess = [ backup.conflictingService ]; - onFailure = [ backup.conflictingService ]; - } - ) - ); + |> lib.filter (backup: backup.conflictingService != null) + |> lib.map (backup: { + name = "restic-backups-${backup.name}"; + value = { + unitConfig.Conflicts = [ backup.conflictingService ]; + after = [ backup.conflictingService ]; + onSuccess = [ backup.conflictingService ]; + onFailure = [ backup.conflictingService ]; + }; + }) + |> lib.listToAttrs; }; } diff --git a/modules/system/services/restic/healthchecks.nix b/modules/system/services/restic/healthchecks.nix index b732847..5f60bc6 100644 --- a/modules/system/services/restic/healthchecks.nix +++ b/modules/system/services/restic/healthchecks.nix @@ -7,7 +7,8 @@ let backupsWithHealthchecks = config.custom.services.restic.backups - |> lib.filterAttrs (_: backup: backup.enable && backup.doHealthchecks); + |> lib.attrValues + |> lib.filter (backup: backup.enable && backup.doHealthchecks); in { options.custom.services.restic.backups = lib.mkOption { @@ -20,40 +21,38 @@ in ); }; - config = lib.mkIf (backupsWithHealthchecks != { }) { + config = lib.mkIf (backupsWithHealthchecks != [ ]) { sops.secrets."healthchecks/ping-key" = { }; - systemd.services = lib.mkMerge [ - { - "healthcheck-ping@" = { - description = "Pings healthcheck (%i)"; - serviceConfig.Type = "oneshot"; - scriptArgs = "%i"; - script = '' - ping_key="$(cat ${config.sops.secrets."healthchecks/ping-key".path})" - slug="$(echo "$1" | tr _ /)" + systemd.services = { + "healthcheck-ping@" = { + description = "Pings healthcheck (%i)"; + serviceConfig.Type = "oneshot"; + scriptArgs = "%i"; + script = '' + ping_key="$(cat ${config.sops.secrets."healthchecks/ping-key".path})" + slug="$(echo "$1" | tr _ /)" - ${lib.getExe pkgs.curl} \ - --fail \ - --silent \ - --show-error \ - --max-time 10 \ - --retry 5 "https://hc-ping.com/$ping_key/$slug?create=1" - ''; + ${lib.getExe pkgs.curl} \ + --fail \ + --silent \ + --show-error \ + --max-time 10 \ + --retry 5 "https://hc-ping.com/$ping_key/$slug?create=1" + ''; + }; + } + // ( + backupsWithHealthchecks + |> lib.map (backup: { + name = "restic-backups-${backup.name}"; + value = { + wants = [ "healthcheck-ping@${backup.name}-backup_start.service" ]; + onSuccess = [ "healthcheck-ping@${backup.name}-backup.service" ]; + onFailure = [ "healthcheck-ping@${backup.name}-backup_fail.service" ]; }; - } - - ( - backupsWithHealthchecks - |> lib.mapAttrs' ( - name: _: - lib.nameValuePair "restic-backups-${name}" { - wants = [ "healthcheck-ping@${name}-backup_start.service" ]; - onSuccess = [ "healthcheck-ping@${name}-backup.service" ]; - onFailure = [ "healthcheck-ping@${name}-backup_fail.service" ]; - } - ) - ) - ]; + }) + |> lib.listToAttrs + ); }; } diff --git a/modules/system/services/restic/restore.nix b/modules/system/services/restic/restore.nix index 6d86081..d5ab77a 100644 --- a/modules/system/services/restic/restore.nix +++ b/modules/system/services/restic/restore.nix @@ -7,7 +7,8 @@ let backupsWithRestoreCommand = config.custom.services.restic.backups - |> lib.filterAttrs (_: backup: backup.enable && backup.restoreCommand.enable); + |> lib.attrValues + |> lib.filter (backup: backup.enable && backup.restoreCommand.enable); in { options.custom.services.restic.backups = lib.mkOption { @@ -33,23 +34,22 @@ in config = { environment.systemPackages = backupsWithRestoreCommand - |> lib.mapAttrsToList ( - name: backup: + |> lib.map ( + backup: + let + inherit (backup) name conflictingService; + inherit (backup.restoreCommand) preRestore postRestore; + hasConflictingService = conflictingService != null; + in pkgs.writeShellApplication { name = "restic-restore-${name}"; - text = - let - inherit (backup) conflictingService; - inherit (backup.restoreCommand) preRestore postRestore; - hasConflictingService = conflictingService != null; - in - '' - ${lib.optionalString hasConflictingService "systemctl stop ${conflictingService}"} - ${preRestore} - restic-${name} restore latest --target / - ${postRestore} - ${lib.optionalString hasConflictingService "systemctl start ${conflictingService}"} - ''; + text = '' + ${lib.optionalString hasConflictingService "systemctl stop ${conflictingService}"} + ${preRestore} + restic-${name} restore latest --target / + ${postRestore} + ${lib.optionalString hasConflictingService "systemctl start ${conflictingService}"} + ''; } ); };