nixos/borgbackup: Add option dumpCommandProducesTar
Add an option `service.borgbackup.jobs.<name>.dumpCommandProducesTar` that allows using `borg import-tar` rather than `borg create` to import an archive.
This commit is contained in:
@@ -89,19 +89,24 @@ let
|
|||||||
${cfg.postInit}
|
${cfg.postInit}
|
||||||
fi
|
fi
|
||||||
''
|
''
|
||||||
+ ''
|
+ (
|
||||||
(
|
let
|
||||||
set -o pipefail
|
import-tar = cfg.dumpCommand != null && cfg.dumpCommandProducesTar;
|
||||||
${lib.optionalString (cfg.dumpCommand != null) ''${lib.escapeShellArg cfg.dumpCommand} | \''}
|
in
|
||||||
borgWrapper create "''${extraArgs[@]}" \
|
''
|
||||||
--compression ${cfg.compression} \
|
(
|
||||||
--exclude-from ${mkExcludeFile cfg} \
|
set -o pipefail
|
||||||
--patterns-from ${mkPatternsFile cfg} \
|
${lib.optionalString (cfg.dumpCommand != null) ''${lib.escapeShellArg cfg.dumpCommand} | \''}
|
||||||
"''${extraCreateArgs[@]}" \
|
borgWrapper ${if import-tar then "import-tar" else "create"} "''${extraArgs[@]}" \
|
||||||
"::$archiveName$archiveSuffix" \
|
--compression ${cfg.compression} \
|
||||||
${if cfg.paths == null then "-" else lib.escapeShellArgs cfg.paths}
|
${lib.optionalString (!import-tar) "--exclude-from ${mkExcludeFile cfg}"} \
|
||||||
)
|
${lib.optionalString (!import-tar) "--patterns-from ${mkPatternsFile cfg}"} \
|
||||||
''
|
"''${extraCreateArgs[@]}" \
|
||||||
|
"::$archiveName$archiveSuffix" \
|
||||||
|
${if cfg.paths == null then "-" else lib.escapeShellArgs cfg.paths}
|
||||||
|
)
|
||||||
|
''
|
||||||
|
)
|
||||||
+ lib.optionalString cfg.appendFailedSuffix ''
|
+ lib.optionalString cfg.appendFailedSuffix ''
|
||||||
borgWrapper rename "''${extraArgs[@]}" \
|
borgWrapper rename "''${extraArgs[@]}" \
|
||||||
"::$archiveName$archiveSuffix" "$archiveName"
|
"::$archiveName$archiveSuffix" "$archiveName"
|
||||||
@@ -310,6 +315,18 @@ let
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mkCreateCommandAssertions = name: cfg: {
|
||||||
|
assertion =
|
||||||
|
(cfg.exclude == [ ] && cfg.patterns == [ ])
|
||||||
|
|| cfg.dumpCommand == null
|
||||||
|
|| !cfg.dumpCommandProducesTar;
|
||||||
|
message = ''
|
||||||
|
Options borgbackup.jobs.${name}.exclude and borgbackup.jobs.${name}.patterns
|
||||||
|
have no effect when dumpCommand is specified and dumpCommandProducesTar is
|
||||||
|
true, as they are not supported by "borg import-tar".
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
mkRemovableDeviceAssertions = name: cfg: {
|
mkRemovableDeviceAssertions = name: cfg: {
|
||||||
assertion = !(isLocalPath cfg.repo) -> !cfg.removableDevice;
|
assertion = !(isLocalPath cfg.repo) -> !cfg.removableDevice;
|
||||||
message = ''
|
message = ''
|
||||||
@@ -398,6 +415,17 @@ in
|
|||||||
example = "/path/to/createZFSsend.sh";
|
example = "/path/to/createZFSsend.sh";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dumpCommandProducesTar = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Set to `true` to use {command}`borg import-tar` instead of
|
||||||
|
{command}`borg create` when creating an archive. Has no effect
|
||||||
|
when {option}`dumpCommand` is unset.
|
||||||
|
'';
|
||||||
|
example = true;
|
||||||
|
};
|
||||||
|
|
||||||
repo = lib.mkOption {
|
repo = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
description = "Remote or local repository to back up to.";
|
description = "Remote or local repository to back up to.";
|
||||||
@@ -556,6 +584,8 @@ in
|
|||||||
description = ''
|
description = ''
|
||||||
Exclude paths matching any of the given patterns. See
|
Exclude paths matching any of the given patterns. See
|
||||||
{command}`borg help patterns` for pattern syntax.
|
{command}`borg help patterns` for pattern syntax.
|
||||||
|
|
||||||
|
Conflicts with {option}`dumpCommandProducesTar`.
|
||||||
'';
|
'';
|
||||||
default = [ ];
|
default = [ ];
|
||||||
example = [
|
example = [
|
||||||
@@ -571,6 +601,8 @@ in
|
|||||||
matching patterns is used, so if an include pattern (prefix `+`)
|
matching patterns is used, so if an include pattern (prefix `+`)
|
||||||
matches before an exclude pattern (prefix `-`), the file is
|
matches before an exclude pattern (prefix `-`), the file is
|
||||||
backed up. See [{command}`borg help patterns`](https://borgbackup.readthedocs.io/en/stable/usage/help.html#borg-patterns) for pattern syntax.
|
backed up. See [{command}`borg help patterns`](https://borgbackup.readthedocs.io/en/stable/usage/help.html#borg-patterns) for pattern syntax.
|
||||||
|
|
||||||
|
Conflicts with {option}`dumpCommandProducesTar`.
|
||||||
'';
|
'';
|
||||||
default = [ ];
|
default = [ ];
|
||||||
example = [
|
example = [
|
||||||
@@ -888,6 +920,7 @@ in
|
|||||||
lib.mapAttrsToList mkPassAssertion jobs
|
lib.mapAttrsToList mkPassAssertion jobs
|
||||||
++ lib.mapAttrsToList mkKeysAssertion repos
|
++ lib.mapAttrsToList mkKeysAssertion repos
|
||||||
++ lib.mapAttrsToList mkSourceAssertions jobs
|
++ lib.mapAttrsToList mkSourceAssertions jobs
|
||||||
|
++ lib.mapAttrsToList mkCreateCommandAssertions jobs
|
||||||
++ lib.mapAttrsToList mkRemovableDeviceAssertions jobs;
|
++ lib.mapAttrsToList mkRemovableDeviceAssertions jobs;
|
||||||
|
|
||||||
systemd.tmpfiles.settings = lib.mapAttrs' mkTmpfiles jobs;
|
systemd.tmpfiles.settings = lib.mapAttrs' mkTmpfiles jobs;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ let
|
|||||||
keepFile = "important_file";
|
keepFile = "important_file";
|
||||||
keepFileData = "important_data";
|
keepFileData = "important_data";
|
||||||
localRepo = "/root/back:up";
|
localRepo = "/root/back:up";
|
||||||
|
localTarRepo = "/root/backup-tar";
|
||||||
# a repository on a file system which is not mounted automatically
|
# a repository on a file system which is not mounted automatically
|
||||||
localRepoMount = "/noAutoMount";
|
localRepoMount = "/noAutoMount";
|
||||||
archiveName = "my_archive";
|
archiveName = "my_archive";
|
||||||
@@ -47,7 +48,7 @@ in
|
|||||||
|
|
||||||
nodes = {
|
nodes = {
|
||||||
client =
|
client =
|
||||||
{ ... }:
|
{ lib, pkgs, ... }:
|
||||||
{
|
{
|
||||||
virtualisation.fileSystems.${localRepoMount} = {
|
virtualisation.fileSystems.${localRepoMount} = {
|
||||||
device = "tmpfs";
|
device = "tmpfs";
|
||||||
@@ -93,6 +94,20 @@ in
|
|||||||
startAt = [ ];
|
startAt = [ ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
localTar = {
|
||||||
|
dumpCommand = pkgs.writeScript "createTarArchive" ''
|
||||||
|
${lib.getExe pkgs.gnutar} cf - ${dataDir}
|
||||||
|
'';
|
||||||
|
dumpCommandProducesTar = true;
|
||||||
|
repo = localTarRepo;
|
||||||
|
# Make sure in import-tar mode encryption flags are still respected.
|
||||||
|
encryption = {
|
||||||
|
mode = "repokey";
|
||||||
|
inherit passphrase;
|
||||||
|
};
|
||||||
|
startAt = [ ]; # Do not run automatically
|
||||||
|
};
|
||||||
|
|
||||||
remote = {
|
remote = {
|
||||||
paths = dataDir;
|
paths = dataDir;
|
||||||
repo = remoteRepo;
|
repo = remoteRepo;
|
||||||
@@ -231,6 +246,19 @@ in
|
|||||||
# Make sure disabling wrapper works
|
# Make sure disabling wrapper works
|
||||||
client.fail("command -v borg-job-localMount")
|
client.fail("command -v borg-job-localMount")
|
||||||
|
|
||||||
|
with subtest("localTar"):
|
||||||
|
borg = "BORG_PASSPHRASE='${passphrase}' borg"
|
||||||
|
client.systemctl("start --wait borgbackup-job-localTar")
|
||||||
|
client.fail("systemctl is-failed borgbackup-job-localTar")
|
||||||
|
archiveName, = client.succeed("{} list --format '{{archive}}{{NL}}' '${localTarRepo}'".format(borg)).strip().split("\n")
|
||||||
|
# Since excludes are not supported by import-tar, we expect to find exclude file, too
|
||||||
|
client.succeed(
|
||||||
|
"{} list '${localTarRepo}::{}' | grep -qF '${excludeFile}'".format(borg, archiveName)
|
||||||
|
)
|
||||||
|
# Make sure keepFile has the correct content
|
||||||
|
client.succeed("{} extract '${localTarRepo}::{}'".format(borg, archiveName))
|
||||||
|
assert "${keepFileData}" in client.succeed("cat ${dataDir}/${keepFile}")
|
||||||
|
|
||||||
with subtest("remote"):
|
with subtest("remote"):
|
||||||
borg = "BORG_RSH='ssh -oStrictHostKeyChecking=no -i /root/id_ed25519' borg"
|
borg = "BORG_RSH='ssh -oStrictHostKeyChecking=no -i /root/id_ed25519' borg"
|
||||||
server.wait_for_unit("sshd.service")
|
server.wait_for_unit("sshd.service")
|
||||||
|
|||||||
Reference in New Issue
Block a user