nixos: refactor tarsnap module

The Tarsnap module is now far more flexible, allowing individual
archives with individual options to be specified at will, allowing
granular backup schedules, etc.

Signed-off-by: Austin Seipp <aseipp@pobox.com>
This commit is contained in:
Austin Seipp 2014-04-28 18:15:14 -05:00
parent 7faaa9e6da
commit 9242ed1fe2

View File

@ -7,9 +7,9 @@ let
optionalNullStr = e: v: if e == null then "" else v; optionalNullStr = e: v: if e == null then "" else v;
configFile = pkgs.writeText "tarsnap.conf" '' configFile = cfg: ''
cachedir ${cfg.cachedir} cachedir ${config.services.tarsnap.cachedir}
keyfile ${cfg.keyfile} keyfile ${config.services.tarsnap.keyfile}
${optionalString cfg.nodump "nodump"} ${optionalString cfg.nodump "nodump"}
${optionalString cfg.printStats "print-stats"} ${optionalString cfg.printStats "print-stats"}
${optionalNullStr cfg.checkpointBytes "checkpoint-bytes "+cfg.checkpointBytes} ${optionalNullStr cfg.checkpointBytes "checkpoint-bytes "+cfg.checkpointBytes}
@ -39,15 +39,15 @@ in
''; '';
}; };
label = mkOption { keyfile = mkOption {
type = types.str; type = types.path;
default = "nixos"; default = "/root/tarsnap.key";
description = '' description = ''
Specifies the label for archives created by Tarsnap. The Path to the keyfile which identifies the machine
full name will be associated with your Tarsnap account. This file can
<literal>label-$(date+"%Y%m%d%H%M%S")</literal>. For be created using the
example, by default your backups will look similar to <literal>tarsnap-keygen</literal> utility, and
<literal>nixos-20140301011501</literal>. providing your Tarsnap login credentials.
''; '';
}; };
@ -55,122 +55,158 @@ in
type = types.path; type = types.path;
default = "/var/cache/tarsnap"; default = "/var/cache/tarsnap";
description = '' description = ''
Tarsnap operations use a "cache directory" which allows Tarsnap operations use a "cache directory" which
Tarsnap to identify which blocks of data have been allows Tarsnap to identify which blocks of data have
previously stored; this directory is specified via the been previously stored; this directory is specified
<literal>cachedir</literal> option. If the cache directory via the <literal>cachedir</literal> option. If the
is lost or out of date, tarsnap creation/deletion operations cache directory is lost or out of date, tarsnap
will exit with an error message instructing you to run creation/deletion operations will exit with an error
<literal>tarsnap --fsck</literal> to regenerate the cache message instructing you to run <literal>tarsnap
directory. --fsck</literal> to regenerate the cache directory.
''; '';
}; };
keyfile = mkOption { config = mkOption {
type = types.path; type = types.attrsOf (types.submodule (
default = "/root/tarsnap.key"; {
description = '' options = {
Path to the keyfile which identifies the machine associated nodump = mkOption {
with your Tarsnap account. This file can be created using type = types.bool;
the <literal>tarsnap-keygen</literal> utility, and providing default = true;
your Tarsnap login credentials. description = ''
If set to <literal>true</literal>, then don't
archive files which have the
<literal>nodump</literal> flag set.
'';
};
printStats = mkOption {
type = types.bool;
default = true;
description = "Print statistics when creating archives.";
};
checkpointBytes = mkOption {
type = types.nullOr types.str;
default = "1G";
description = ''
Create a checkpoint per a particular amount of
uploaded data. By default, Tarsnap will create
checkpoints once per GB of data uploaded. At
minimum, <literal>checkpointBytes</literal> must be
1GB.
Can also be set to <literal>null</literal> to
disable checkpointing.
'';
};
period = mkOption {
type = types.str;
default = "15 01 * * *";
description = ''
This option defines (in the format used by cron)
when tarsnap is run for backups. The default is to
backup the specified paths at 01:15 at night every
day.
'';
};
aggressiveNetworking = mkOption {
type = types.bool;
default = false;
description = ''
Aggressive network behaviour: Use multiple TCP
connections when writing archives. Use of this
option is recommended only in cases where TCP
congestion control is known to be the limiting
factor in upload performance.
'';
};
directories = mkOption {
type = types.listOf types.path;
default = [];
description = "List of filesystem paths to archive.";
};
excludes = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Exclude files and directories matching the specified
patterns.
'';
};
includes = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Include only files and directories matching the
specified patterns.
Note that exclusions specified via
<literal>excludes</literal> take precedence over
inclusions.
'';
};
lowmem = mkOption {
type = types.bool;
default = false;
description = ''
Attempt to reduce tarsnap memory consumption. This
option will slow down the process of creating
archives, but may help on systems where the average
size of files being backed up is less than 1 MB.
'';
};
verylowmem = mkOption {
type = types.bool;
default = false;
description = ''
Try even harder to reduce tarsnap memory
consumption. This can significantly slow down
tarsnap, but reduces its memory usage by an
additional factor of 2 beyond what the
<literal>lowmem</literal> option does.
'';
};
};
}
));
default = {};
example = literalExample ''
{
nixos =
{ directories = [ "/home" "/root/ssl" ];
};
gamedata =
{ directories = [ "/var/lib/minecraft "];
period = "*/30 * * * *";
};
}
''; '';
};
nodump = mkOption {
type = types.bool;
default = true;
description = '' description = ''
If set to <literal>true</literal>, then don't archive files Configuration of a Tarsnap archive. In the example, your
which have the <literal>nodump</literal> flag set. machine will have two tarsnap archives:
''; <literal>gamedata</literal> (backed up every 30 minutes) and
}; <literal>nixos</literal> (backed up at 1:15 AM every night by
default). You can control individual archive backups using
printStats = mkOption { <literal>systemctl</literal>, using the
type = types.bool; <literal>tarsnap@nixos</literal> or
default = true; <literal>tarsnap@gamedata</literal> units. For example,
description = "Print statistics when creating archives."; <literal>systemctl start tarsnap@nixos</literal> will
}; immediately create a new NixOS archive. By default, archives
are suffixed with the timestamp of when they were started,
checkpointBytes = mkOption { down to second resolution. This means you can use GNU
type = types.nullOr types.str; <literal>sort</literal> to sort output easily.
default = "1G";
description = ''
Create a checkpoint per a particular amount of uploaded
data. By default, Tarsnap will create checkpoints once per
GB of data uploaded. At minimum,
<literal>checkpointBytes</literal> must be 1GB.
Can also be set to <literal>null</literal> to disable
checkpointing.
'';
};
period = mkOption {
type = types.str;
default = "15 01 * * *";
description = ''
This option defines (in the format used by cron) when
tarsnap is run for backups. The default is to backup the
specified paths at 01:15 at night every day.
'';
};
aggressiveNetworking = mkOption {
type = types.bool;
default = false;
description = ''
Aggressive network behaviour: Use multiple TCP connections
when writing archives. Use of this option is recommended
only in cases where TCP congestion control is known to be
the limiting factor in upload performance.
'';
};
directories = mkOption {
type = types.listOf types.path;
default = [];
description = "List of filesystem paths to archive.";
};
excludes = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Exclude files and directories matching the specified patterns.
'';
};
includes = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Include only files and directories matching the specified patterns.
Note that exclusions specified via
<literal>excludes</literal> take precedence over inclusions.
'';
};
lowmem = mkOption {
type = types.bool;
default = false;
description = ''
Attempt to reduce tarsnap memory consumption. This option
will slow down the process of creating archives, but may
help on systems where the average size of files being backed
up is less than 1 MB.
'';
};
verylowmem = mkOption {
type = types.bool;
default = false;
description = ''
Try even harder to reduce tarsnap memory consumption. This
can significantly slow down tarsnap, but reduces its memory
usage by an additional factor of 2 beyond what the
<literal>lowmem</literal> option does.
''; '';
}; };
}; };
@ -178,26 +214,40 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
assertions = assertions =
[ { assertion = cfg.directories != []; (mapAttrsToList (name: cfg:
{ assertion = cfg.directories != [];
message = "Must specify directories for Tarsnap to back up"; message = "Must specify directories for Tarsnap to back up";
} }) cfg.config) ++
(mapAttrsToList (name: cfg:
{ assertion = cfg.lowmem -> !cfg.verylowmem && (cfg.verylowmem -> !cfg.lowmem); { assertion = cfg.lowmem -> !cfg.verylowmem && (cfg.verylowmem -> !cfg.lowmem);
message = "You cannot set both lowmem and verylowmem"; message = "You cannot set both lowmem and verylowmem";
} }) cfg.config);
];
systemd.services."tarsnap@" = {
description = "Tarsnap Backup of '%i'";
requires = [ "network.target" ];
systemd.services.tarsnap-backup = {
description = "Tarsnap Backup process";
path = [ pkgs.tarsnap pkgs.coreutils ]; path = [ pkgs.tarsnap pkgs.coreutils ];
scriptArgs = "%i";
script = '' script = ''
mkdir -p -m 0755 $(dirname ${cfg.cachedir}) mkdir -p -m 0755 $(dirname ${cfg.cachedir})
mkdir -p -m 0600 ${cfg.cachedir} mkdir -p -m 0600 ${cfg.cachedir}
exec tarsnap --configfile ${configFile} -c -f ${cfg.label}-$(date +"%Y%m%d%H%M%S") ${concatStringsSep " " cfg.directories} DIRS=`cat /etc/tarsnap/$1.dirs`
exec tarsnap --configfile /etc/tarsnap/$1.conf -c -f $1-$(date +"%Y%m%d%H%M%S") $DIRS
''; '';
}; };
services.cron.systemCronJobs = optional cfg.enable services.cron.systemCronJobs = mapAttrsToList (name: cfg:
"${cfg.period} root ${config.systemd.package}/bin/systemctl start tarsnap-backup.service"; "${cfg.period} root ${config.systemd.package}/bin/systemctl start tarsnap@${name}"
) cfg.config;
environment.etc =
(mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.conf"
{ text = configFile cfg;
}) cfg.config) //
(mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.dirs"
{ text = concatStringsSep " " cfg.directories;
}) cfg.config);
environment.systemPackages = [ pkgs.tarsnap ]; environment.systemPackages = [ pkgs.tarsnap ];
}; };