From dbb69f82c6d3ef080f42f478fc366445539df757 Mon Sep 17 00:00:00 2001 From: ajs124 Date: Thu, 24 Aug 2023 01:31:58 +0200 Subject: [PATCH] nixos/restic: add wrapper scripts that set parameters for backup and use in test --- .../manual/release-notes/rl-2311.section.md | 2 ++ nixos/modules/services/backup/restic.nix | 30 ++++++++++++++++++- nixos/tests/restic.nix | 20 ++++++------- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md index 24c044ece7e..923c1146440 100644 --- a/nixos/doc/manual/release-notes/rl-2311.section.md +++ b/nixos/doc/manual/release-notes/rl-2311.section.md @@ -201,6 +201,8 @@ The module update takes care of the new config syntax and the data itself (user - `services.nginx` gained a `defaultListen` option at server-level with support for PROXY protocol listeners, also `proxyProtocol` is now exposed in `services.nginx.virtualHosts..listen` option. It is now possible to run PROXY listeners and non-PROXY listeners at a server-level, see [#213510](https://github.com/NixOS/nixpkgs/pull/213510/) for more details. +- `services.restic.backups` now adds wrapper scripts to your system path, which set the same environment variables as the service, so restic operations can easly be run from the command line. This behavior can be disabled by setting `createWrapper` to `false`, per backup configuration. + - `services.prometheus.exporters` has a new exporter to monitor electrical power consumption based on PowercapRAPL sensor called [Scaphandre](https://github.com/hubblo-org/scaphandre), see [#239803](https://github.com/NixOS/nixpkgs/pull/239803) for more details. - The module `services.calibre-server` has new options to configure the `host`, `port`, `auth.enable`, `auth.mode` and `auth.userDb` path, see [#216497](https://github.com/NixOS/nixpkgs/pull/216497/) for more details. diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix index 60afb15ee87..70be32aa8c3 100644 --- a/nixos/modules/services/backup/restic.nix +++ b/nixos/modules/services/backup/restic.nix @@ -260,6 +260,16 @@ in Restic package to use. ''; }; + + createWrapper = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to generate and add a script to the system path, that has the same environment variables set + as the systemd service. This can be used to e.g. mount snapshots or perform other opterations, without + having to manually specify most options. + ''; + }; }; })); default = { }; @@ -316,7 +326,8 @@ in in nameValuePair "restic-backups-${name}" ({ environment = { - RESTIC_CACHE_DIR = "%C/restic-backups-${name}"; + # not %C, because that wouldn't work in the wrapper script + RESTIC_CACHE_DIR = "/var/cache/restic-backups-${name}"; RESTIC_PASSWORD_FILE = backup.passwordFile; RESTIC_REPOSITORY = backup.repository; RESTIC_REPOSITORY_FILE = backup.repositoryFile; @@ -376,5 +387,22 @@ in timerConfig = backup.timerConfig; }) config.services.restic.backups; + + # generate wrapper scripts, as described in the createWrapper option + environment.systemPackages = lib.mapAttrsToList (name: backup: let + extraOptions = lib.concatMapStrings (arg: " -o ${arg}") backup.extraOptions; + resticCmd = "${backup.package}/bin/restic${extraOptions}"; + in pkgs.writeShellScriptBin "restic-${name}" '' + set -a # automatically export variables + ${lib.optionalString (backup.environmentFile != null) "source ${backup.environmentFile}"} + # set same environment variables as the systemd service + ${lib.pipe config.systemd.services."restic-backups-${name}".environment [ + (lib.filterAttrs (_: v: v != null)) + (lib.mapAttrsToList (n: v: "${n}=${v}")) + (lib.concatStringsSep "\n") + ]} + + exec ${resticCmd} $@ + '') (lib.filterAttrs (_: v: v.createWrapper) config.services.restic.backups); }; } diff --git a/nixos/tests/restic.nix b/nixos/tests/restic.nix index 626049e7334..3b9ea2f85b1 100644 --- a/nixos/tests/restic.nix +++ b/nixos/tests/restic.nix @@ -97,9 +97,9 @@ import ./make-test-python.nix ( server.start() server.wait_for_unit("dbus.socket") server.fail( - "${pkgs.restic}/bin/restic -r ${remoteRepository} -p ${passwordFile} snapshots", - '${pkgs.restic}/bin/restic -r ${remoteFromFileRepository} -p ${passwordFile} snapshots"', - "${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots", + "restic-remotebackup snapshots", + 'restic-remote-from-file-backup snapshots"', + "restic-rclonebackup snapshots", "grep 'backup.* /opt' /root/fake-restic.log", ) server.succeed( @@ -112,20 +112,20 @@ import ./make-test-python.nix ( "timedatectl set-time '2016-12-13 13:45'", "systemctl start restic-backups-remotebackup.service", "rm /root/backupCleanupCommand", - '${pkgs.restic}/bin/restic -r ${remoteRepository} -p ${passwordFile} snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"', + 'restic-remotebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"', # test that restoring that snapshot produces the same directory "mkdir /tmp/restore-1", - "${pkgs.restic}/bin/restic -r ${remoteRepository} -p ${passwordFile} restore latest -t /tmp/restore-1", + "restic-remotebackup restore latest -t /tmp/restore-1", "diff -ru ${testDir} /tmp/restore-1/opt", # test that remote-from-file-backup produces a snapshot "systemctl start restic-backups-remote-from-file-backup.service", - '${pkgs.restic}/bin/restic -r ${remoteFromFileRepository} -p ${passwordFile} snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"', + 'restic-remote-from-file-backup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"', # test that rclonebackup produces a snapshot "systemctl start restic-backups-rclonebackup.service", - '${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"', + 'restic-rclonebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"', # test that custompackage runs both `restic backup` and `restic check` with reasonable commandlines "systemctl start restic-backups-custompackage.service", @@ -158,12 +158,12 @@ import ./make-test-python.nix ( "rm /root/backupCleanupCommand", "systemctl start restic-backups-rclonebackup.service", - '${pkgs.restic}/bin/restic -r ${remoteRepository} -p ${passwordFile} snapshots --json | ${pkgs.jq}/bin/jq "length | . == 4"', - '${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots --json | ${pkgs.jq}/bin/jq "length | . == 4"', + 'restic-remotebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 4"', + 'restic-rclonebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 4"', # test that remoteprune brings us back to 1 snapshot in remotebackup "systemctl start restic-backups-remoteprune.service", - '${pkgs.restic}/bin/restic -r ${remoteRepository} -p ${passwordFile} snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"', + 'restic-remotebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"', ) '';