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`.
This commit is contained in:
Jacob Greenleaf 2022-10-27 19:57:28 -07:00
parent 9063accddd
commit 0111e9547e
4 changed files with 51 additions and 4 deletions

View file

@ -44,6 +44,14 @@
instead.
</para>
</listitem>
<listitem>
<para>
<literal>borgbackup</literal> module now has an option for
inhibiting system sleep while backups are running, defaulting
to off (not inhibiting sleep), available as
<link linkend="opt-services.borgbackup.jobs._name_.inhibitsSleep"><literal>services.borgbackup.jobs.&lt;name&gt;.inhibitsSleep</literal></link>.
</para>
</listitem>
<listitem>
<para>
The EC2 image module no longer fetches instance metadata in

View file

@ -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.<name>.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`

View file

@ -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 ''

View file

@ -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")
'';
})