From 0111e9547e857021a3cdab7ac5ba85707cccd654 Mon Sep 17 00:00:00 2001 From: Jacob Greenleaf Date: Thu, 27 Oct 2022 19:57:28 -0700 Subject: [PATCH] nixos/borgbackup: Add option for inhibiting sleep Adds a new option for backup jobs `inhibitsSleep` which prevents the system from going to sleep while a backup is in progress. Uses `systemd-inhibit`, which holds a "lock" that prevents the system from sleeping while the process it invokes is running. This did require wrapping the existing backup script using `writeShellScript` so that it could be run by `systemd-inhibit`. --- .../from_md/release-notes/rl-2305.section.xml | 8 ++++++ .../manual/release-notes/rl-2305.section.md | 2 ++ nixos/modules/services/backup/borgbackup.nix | 25 ++++++++++++++++--- nixos/tests/borgbackup.nix | 20 +++++++++++++++ 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml index 757a719bfefd..a7ae088d0303 100644 --- a/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml +++ b/nixos/doc/manual/from_md/release-notes/rl-2305.section.xml @@ -44,6 +44,14 @@ instead. + + + borgbackup module now has an option for + inhibiting system sleep while backups are running, defaulting + to off (not inhibiting sleep), available as + services.borgbackup.jobs.<name>.inhibitsSleep. + + The EC2 image module no longer fetches instance metadata in diff --git a/nixos/doc/manual/release-notes/rl-2305.section.md b/nixos/doc/manual/release-notes/rl-2305.section.md index 1b105fdd1f3f..34220141cca1 100644 --- a/nixos/doc/manual/release-notes/rl-2305.section.md +++ b/nixos/doc/manual/release-notes/rl-2305.section.md @@ -22,6 +22,8 @@ In addition to numerous new and upgraded packages, this release has the followin - `carnix` and `cratesIO` has been removed due to being unmaintained, use alternatives such as [naersk](https://github.com/nix-community/naersk) and [crate2nix](https://github.com/kolloch/crate2nix) instead. +- `borgbackup` module now has an option for inhibiting system sleep while backups are running, defaulting to off (not inhibiting sleep), available as [`services.borgbackup.jobs..inhibitsSleep`](#opt-services.borgbackup.jobs._name_.inhibitsSleep). + - The EC2 image module no longer fetches instance metadata in stage-1. This results in a significantly smaller initramfs, since network drivers no longer need to be included, and faster boots, since metadata fetching can happen in parallel with startup of other services. This breaks services which rely on metadata being present by the time stage-2 is entered. Anything which reads EC2 metadata from `/etc/ec2-metadata` should now have an `after` dependency on `fetch-ec2-metadata.service` diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix index 7b29eb41e72a..1d582c7da1c1 100644 --- a/nixos/modules/services/backup/borgbackup.nix +++ b/nixos/modules/services/backup/borgbackup.nix @@ -19,7 +19,8 @@ let concatStringsSep " " (mapAttrsToList (x: y: "--keep-${x}=${toString y}") cfg.prune.keep); - mkBackupScript = cfg: '' + mkBackupScript = name: cfg: pkgs.writeShellScript "${name}-script" ('' + set -e on_exit() { exitStatus=$? @@ -61,7 +62,7 @@ let ${optionalString (cfg.prune.prefix != null) "--prefix ${escapeShellArg cfg.prune.prefix} \\"} $extraPruneArgs ${cfg.postPrune} - ''; + ''); mkPassEnv = cfg: with cfg.encryption; if passCommand != null then @@ -73,12 +74,19 @@ let mkBackupService = name: cfg: let userHome = config.users.users.${cfg.user}.home; - in nameValuePair "borgbackup-job-${name}" { + backupJobName = "borgbackup-job-${name}"; + backupScript = mkBackupScript backupJobName cfg; + in nameValuePair backupJobName { description = "BorgBackup job ${name}"; path = with pkgs; [ borgbackup openssh ]; - script = mkBackupScript cfg; + script = "exec " + optionalString cfg.inhibitsSleep ''\ + ${pkgs.systemd}/bin/systemd-inhibit \ + --who="borgbackup" \ + --what="sleep" \ + --why="Scheduled backup" \ + '' + backupScript; serviceConfig = { User = cfg.user; Group = cfg.group; @@ -341,6 +349,15 @@ in { ''; }; + inhibitsSleep = mkOption { + default = false; + type = types.bool; + example = true; + description = lib.mdDoc '' + Prevents the system from sleeping while backing up. + ''; + }; + user = mkOption { type = types.str; description = lib.mdDoc '' diff --git a/nixos/tests/borgbackup.nix b/nixos/tests/borgbackup.nix index d3cd6c66bfeb..9afe4d537da4 100644 --- a/nixos/tests/borgbackup.nix +++ b/nixos/tests/borgbackup.nix @@ -99,6 +99,18 @@ in { environment.BORG_RSH = "ssh -oStrictHostKeyChecking=no -i /root/id_ed25519"; }; + sleepInhibited = { + inhibitsSleep = true; + # Blocks indefinitely while "backing up" so that we can try to suspend the local system while it's hung + dumpCommand = pkgs.writeScript "sleepInhibited" '' + cat /dev/zero + ''; + repo = remoteRepo; + encryption.mode = "none"; + startAt = [ ]; + environment.BORG_RSH = "ssh -oStrictHostKeyChecking=no -i /root/id_ed25519"; + }; + }; }; @@ -204,5 +216,13 @@ in { client.wait_for_unit("network.target") client.systemctl("start --wait borgbackup-job-commandFail") client.succeed("systemctl is-failed borgbackup-job-commandFail") + + with subtest("sleepInhibited"): + server.wait_for_unit("sshd.service") + client.wait_for_unit("network.target") + client.fail("systemd-inhibit --list | grep -q borgbackup") + client.systemctl("start borgbackup-job-sleepInhibited") + client.wait_until_succeeds("systemd-inhibit --list | grep -q borgbackup") + client.systemctl("stop borgbackup-job-sleepInhibited") ''; })