nixos/borgbackup: allow dump scripts as stdin inputs
borg is able to process stdin during backups when backing up the special path -, which can be very useful for backing up things that can be streamed (eg database dumps, zfs snapshots).
This commit is contained in:
parent
c47fcb70c6
commit
1fa5e13f30
2 changed files with 68 additions and 8 deletions
|
@ -42,12 +42,16 @@ let
|
|||
${cfg.postInit}
|
||||
fi
|
||||
'' + ''
|
||||
borg create $extraArgs \
|
||||
--compression ${cfg.compression} \
|
||||
--exclude-from ${mkExcludeFile cfg} \
|
||||
$extraCreateArgs \
|
||||
"::$archiveName$archiveSuffix" \
|
||||
${escapeShellArgs cfg.paths}
|
||||
(
|
||||
set -o pipefail
|
||||
${optionalString (cfg.dumpCommand != null) ''${escapeShellArg cfg.dumpCommand} | \''}
|
||||
borg create $extraArgs \
|
||||
--compression ${cfg.compression} \
|
||||
--exclude-from ${mkExcludeFile cfg} \
|
||||
$extraCreateArgs \
|
||||
"::$archiveName$archiveSuffix" \
|
||||
${if cfg.paths == null then "-" else escapeShellArgs cfg.paths}
|
||||
)
|
||||
'' + optionalString cfg.appendFailedSuffix ''
|
||||
borg rename $extraArgs \
|
||||
"::$archiveName$archiveSuffix" "$archiveName"
|
||||
|
@ -182,6 +186,14 @@ let
|
|||
+ " without at least one public key";
|
||||
};
|
||||
|
||||
mkSourceAssertions = name: cfg: {
|
||||
assertion = count isNull [ cfg.dumpCommand cfg.paths ] == 1;
|
||||
message = ''
|
||||
Exactly one of borgbackup.jobs.${name}.paths or borgbackup.jobs.${name}.dumpCommand
|
||||
must be set.
|
||||
'';
|
||||
};
|
||||
|
||||
mkRemovableDeviceAssertions = name: cfg: {
|
||||
assertion = !(isLocalPath cfg.repo) -> !cfg.removableDevice;
|
||||
message = ''
|
||||
|
@ -240,11 +252,25 @@ in {
|
|||
options = {
|
||||
|
||||
paths = mkOption {
|
||||
type = with types; coercedTo str lib.singleton (listOf str);
|
||||
description = "Path(s) to back up.";
|
||||
type = with types; nullOr (coercedTo str lib.singleton (listOf str));
|
||||
default = null;
|
||||
description = ''
|
||||
Path(s) to back up.
|
||||
Mutually exclusive with <option>dumpCommand</option>.
|
||||
'';
|
||||
example = "/home/user";
|
||||
};
|
||||
|
||||
dumpCommand = mkOption {
|
||||
type = with types; nullOr path;
|
||||
default = null;
|
||||
description = ''
|
||||
Backup the stdout of this program instead of filesystem paths.
|
||||
Mutually exclusive with <option>paths</option>.
|
||||
'';
|
||||
example = "/path/to/createZFSsend.sh";
|
||||
};
|
||||
|
||||
repo = mkOption {
|
||||
type = types.str;
|
||||
description = "Remote or local repository to back up to.";
|
||||
|
@ -657,6 +683,7 @@ in {
|
|||
assertions =
|
||||
mapAttrsToList mkPassAssertion jobs
|
||||
++ mapAttrsToList mkKeysAssertion repos
|
||||
++ mapAttrsToList mkSourceAssertions jobs
|
||||
++ mapAttrsToList mkRemovableDeviceAssertions jobs;
|
||||
|
||||
system.activationScripts = mapAttrs' mkActivationScript jobs;
|
||||
|
|
|
@ -81,6 +81,24 @@ in {
|
|||
environment.BORG_RSH = "ssh -oStrictHostKeyChecking=no -i /root/id_ed25519.appendOnly";
|
||||
};
|
||||
|
||||
commandSuccess = {
|
||||
dumpCommand = pkgs.writeScript "commandSuccess" ''
|
||||
echo -n test
|
||||
'';
|
||||
repo = remoteRepo;
|
||||
encryption.mode = "none";
|
||||
startAt = [ ];
|
||||
environment.BORG_RSH = "ssh -oStrictHostKeyChecking=no -i /root/id_ed25519";
|
||||
};
|
||||
|
||||
commandFail = {
|
||||
dumpCommand = "${pkgs.coreutils}/bin/false";
|
||||
repo = remoteRepo;
|
||||
encryption.mode = "none";
|
||||
startAt = [ ];
|
||||
environment.BORG_RSH = "ssh -oStrictHostKeyChecking=no -i /root/id_ed25519";
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -171,5 +189,20 @@ in {
|
|||
client.fail("{} list borg\@server:wrong".format(borg))
|
||||
|
||||
# TODO: Make sure that data is not actually deleted
|
||||
|
||||
with subtest("commandSuccess"):
|
||||
server.wait_for_unit("sshd.service")
|
||||
client.wait_for_unit("network.target")
|
||||
client.systemctl("start --wait borgbackup-job-commandSuccess")
|
||||
client.fail("systemctl is-failed borgbackup-job-commandSuccess")
|
||||
id = client.succeed("borg-job-commandSuccess list | tail -n1 | cut -d' ' -f1").strip()
|
||||
client.succeed(f"borg-job-commandSuccess extract ::{id} stdin")
|
||||
assert "test" == client.succeed("cat stdin")
|
||||
|
||||
with subtest("commandFail"):
|
||||
server.wait_for_unit("sshd.service")
|
||||
client.wait_for_unit("network.target")
|
||||
client.systemctl("start --wait borgbackup-job-commandFail")
|
||||
client.succeed("systemctl is-failed borgbackup-job-commandFail")
|
||||
'';
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue