3
0
Fork 0
forked from mirrors/nixpkgs

Merge pull request #120622 from symphorien/duplicity-master

nixos/duplicity: enable to prevent backup from growing infinitely
This commit is contained in:
Guillaume Girol 2021-05-20 19:00:59 +00:00 committed by GitHub
commit 0d5fa1cff3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,16 +1,17 @@
{ config, lib, pkgs, ...}: { config, lib, pkgs, ... }:
with lib; with lib;
let let
cfg = config.services.duplicity; cfg = config.services.duplicity;
stateDirectory = "/var/lib/duplicity"; stateDirectory = "/var/lib/duplicity";
localTarget = if hasPrefix "file://" cfg.targetUrl localTarget =
if hasPrefix "file://" cfg.targetUrl
then removePrefix "file://" cfg.targetUrl else null; then removePrefix "file://" cfg.targetUrl else null;
in { in
{
options.services.duplicity = { options.services.duplicity = {
enable = mkEnableOption "backups with duplicity"; enable = mkEnableOption "backups with duplicity";
@ -24,7 +25,7 @@ in {
include = mkOption { include = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = []; default = [ ];
example = [ "/home" ]; example = [ "/home" ];
description = '' description = ''
List of paths to include into the backups. See the FILE SELECTION List of paths to include into the backups. See the FILE SELECTION
@ -35,7 +36,7 @@ in {
exclude = mkOption { exclude = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = []; default = [ ];
description = '' description = ''
List of paths to exclude from backups. See the FILE SELECTION section in List of paths to exclude from backups. See the FILE SELECTION section in
<citerefentry><refentrytitle>duplicity</refentrytitle> <citerefentry><refentrytitle>duplicity</refentrytitle>
@ -82,14 +83,60 @@ in {
extraFlags = mkOption { extraFlags = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = []; default = [ ];
example = [ "--full-if-older-than" "1M" ]; example = [ "--backend-retry-delay" "100" ];
description = '' description = ''
Extra command-line flags passed to duplicity. See Extra command-line flags passed to duplicity. See
<citerefentry><refentrytitle>duplicity</refentrytitle> <citerefentry><refentrytitle>duplicity</refentrytitle>
<manvolnum>1</manvolnum></citerefentry>. <manvolnum>1</manvolnum></citerefentry>.
''; '';
}; };
fullIfOlderThan = mkOption {
type = types.str;
default = "never";
example = "1M";
description = ''
If <literal>"never"</literal> (the default) always do incremental
backups (the first backup will be a full backup, of course). If
<literal>"always"</literal> always do full backups. Otherwise, this
must be a string representing a duration. Full backups will be made
when the latest full backup is older than this duration. If this is not
the case, an incremental backup is performed.
'';
};
cleanup = {
maxAge = mkOption {
type = types.nullOr types.str;
default = null;
example = "6M";
description = ''
If non-null, delete all backup sets older than the given time. Old backup sets
will not be deleted if backup sets newer than time depend on them.
'';
};
maxFull = mkOption {
type = types.nullOr types.int;
default = null;
example = 2;
description = ''
If non-null, delete all backups sets that are older than the count:th last full
backup (in other words, keep the last count full backups and
associated incremental sets).
'';
};
maxIncr = mkOption {
type = types.nullOr types.int;
default = null;
example = 1;
description = ''
If non-null, delete incremental sets of all backups sets that are
older than the count:th last full backup (in other words, keep only
old full backups and not their increments).
'';
};
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@ -99,18 +146,26 @@ in {
environment.HOME = stateDirectory; environment.HOME = stateDirectory;
serviceConfig = { script =
ExecStart = '' let
${pkgs.duplicity}/bin/duplicity ${escapeShellArgs ( target = escapeShellArg cfg.targetUrl;
[ extra = escapeShellArgs ([ "--archive-dir" stateDirectory ] ++ cfg.extraFlags);
cfg.root dup = "${pkgs.duplicity}/bin/duplicity";
cfg.targetUrl in
"--archive-dir" stateDirectory ''
] set -x
${dup} cleanup ${target} --force ${extra}
${lib.optionalString (cfg.cleanup.maxAge != null) "${dup} remove-older-than ${lib.escapeShellArg cfg.cleanup.maxAge} ${target} --force ${extra}"}
${lib.optionalString (cfg.cleanup.maxFull != null) "${dup} remove-all-but-n-full ${toString cfg.cleanup.maxFull} ${target} --force ${extra}"}
${lib.optionalString (cfg.cleanup.maxIncr != null) "${dup} remove-all-incr-but-n-full ${toString cfg.cleanup.maxIncr} ${target} --force ${extra}"}
exec ${dup} ${if cfg.fullIfOlderThan == "always" then "full" else "incr"} ${lib.escapeShellArgs (
[ cfg.root cfg.targetUrl ]
++ concatMap (p: [ "--include" p ]) cfg.include ++ concatMap (p: [ "--include" p ]) cfg.include
++ concatMap (p: [ "--exclude" p ]) cfg.exclude ++ concatMap (p: [ "--exclude" p ]) cfg.exclude
++ cfg.extraFlags)} ++ (lib.optionals (cfg.fullIfOlderThan != "never" && cfg.fullIfOlderThan != "always") [ "--full-if-older-than" cfg.fullIfOlderThan ])
)} ${extra}
''; '';
serviceConfig = {
PrivateTmp = true; PrivateTmp = true;
ProtectSystem = "strict"; ProtectSystem = "strict";
ProtectHome = "read-only"; ProtectHome = "read-only";
@ -130,7 +185,7 @@ in {
assertions = singleton { assertions = singleton {
# Duplicity will fail if the last file selection option is an include. It # Duplicity will fail if the last file selection option is an include. It
# is not always possible to detect but this simple case can be caught. # is not always possible to detect but this simple case can be caught.
assertion = cfg.include != [] -> cfg.exclude != [] || cfg.extraFlags != []; assertion = cfg.include != [ ] -> cfg.exclude != [ ] || cfg.extraFlags != [ ];
message = '' message = ''
Duplicity will fail if you only specify included paths ("Because the Duplicity will fail if you only specify included paths ("Because the
default is to include all files, the expression is redundant. Exiting default is to include all files, the expression is redundant. Exiting