nixos: refactor tarsnap backup service module

Major changes
- Port to systemd timers: for each archive configuration is created a
  tarsnap@archive-name.timer which triggers the instanced service unit
- Rename the `config` option to `archives`

Minor/superficial improvements
- Restrict tarsnap service capabilities
- Use dirOf builtin
- Set executable bit for owner of tarsnap cache directory
- Set IOSchedulingClass to idle
- Humanize numbers when printing stats
- Rewrite most option descriptions
- Simplify assertion
This commit is contained in:
Joachim Fasting 2015-03-10 08:40:08 +01:00
parent a869c8351c
commit 1bdd12ed69
2 changed files with 88 additions and 89 deletions

View file

@ -112,6 +112,9 @@ in zipModules ([]
# VirtualBox
++ obsolete [ "services" "virtualbox" "enable" ] [ "services" "virtualboxGuest" "enable" ]
# Tarsnap
++ obsolete [ "services" "tarsnap" "config" ] [ "services" "tarsnap" "archives" ]
# proxy
++ obsolete [ "nix" "proxy" ] [ "networking" "proxy" "default" ]

View file

@ -12,6 +12,7 @@ let
keyfile ${config.services.tarsnap.keyfile}
${optionalString cfg.nodump "nodump"}
${optionalString cfg.printStats "print-stats"}
${optionalString cfg.printStats "humanize-numbers"}
${optionalNullStr cfg.checkpointBytes "checkpoint-bytes "+cfg.checkpointBytes}
${optionalString cfg.aggressiveNetworking "aggressive-networking"}
${concatStringsSep "\n" (map (v: "exclude "+v) cfg.excludes)}
@ -27,46 +28,39 @@ in
type = types.bool;
default = false;
description = ''
If enabled, NixOS will periodically create backups of the
specified directories using the <literal>tarsnap</literal>
backup service. This installs a <literal>systemd</literal>
service called <literal>tarsnap-backup</literal> which is
periodically run by cron, or you may run it on-demand.
See the Tarsnap <link
xlink:href='http://www.tarsnap.com/gettingstarted.html'>Getting
Started</link> page.
Enable periodic tarsnap backups.
'';
};
keyfile = mkOption {
type = types.path;
type = types.str;
default = "/root/tarsnap.key";
description = ''
Path to the keyfile which identifies the machine
associated with your Tarsnap account. This file can
be created using the
<literal>tarsnap-keygen</literal> utility, and
providing your Tarsnap login credentials.
The keyfile which associates this machine with your tarsnap
account.
Create the keyfile with <command>tarsnap-keygen</command>.
The keyfile name should be given as a string and not a path, to
avoid the key being copied into the Nix store.
'';
};
cachedir = mkOption {
type = types.path;
type = types.nullOr types.path;
default = "/var/cache/tarsnap";
description = ''
Tarsnap operations use a "cache directory" which
allows Tarsnap to identify which blocks of data have
been previously stored; this directory is specified
via the <literal>cachedir</literal> option. If the
cache directory is lost or out of date, tarsnap
creation/deletion operations will exit with an error
message instructing you to run <literal>tarsnap
--fsck</literal> to regenerate the cache directory.
The cache allows tarsnap to identify previously stored data
blocks, reducing archival time and bandwidth usage.
Should the cache become desynchronized or corrupted, tarsnap
will refuse to run until you manually rebuild the cache with
<command>tarsnap --fsck</command>.
Set to <literal>null</literal> to disable caching.
'';
};
config = mkOption {
archives = mkOption {
type = types.attrsOf (types.submodule (
{
options = {
@ -74,41 +68,44 @@ in
type = types.bool;
default = true;
description = ''
If set to <literal>true</literal>, then don't
archive files which have the
<literal>nodump</literal> flag set.
Exclude files with the <literal>nodump</literal> flag.
'';
};
printStats = mkOption {
type = types.bool;
default = true;
description = "Print statistics when creating archives.";
description = ''
Print global archive statistics upon completion.
The output is available via
<command>systemctl status tarsnap@archive-name</command>.
'';
};
checkpointBytes = mkOption {
type = types.nullOr types.str;
default = "1G";
default = "1GB";
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.
Create a checkpoint every <literal>checkpointBytes</literal>
of uploaded data (optionally specified using an SI prefix).
Can also be set to <literal>null</literal> to
disable checkpointing.
1GB is the minimum value. A higher value is recommended,
as checkpointing is expensive.
Set to <literal>null</literal> to disable checkpointing.
'';
};
period = mkOption {
type = types.str;
default = "15 01 * * *";
default = "01:15";
example = "hourly";
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.
Create archive at this interval.
The format is described in
<citerefentry><refentrytitle>systemd.time</refentrytitle>
<manvolnum>7</manvolnum></citerefentry>.
'';
};
@ -116,11 +113,11 @@ in
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.
Upload data over multiple TCP connections, potentially
increasing tarsnap's bandwidth utilisation at the cost
of slowing down all other network traffic. Not
recommended unless TCP congestion is the dominant
limiting factor.
'';
};
@ -134,8 +131,7 @@ in
type = types.listOf types.str;
default = [];
description = ''
Exclude files and directories matching the specified
patterns.
Exclude files and directories matching these patterns.
'';
};
@ -143,12 +139,10 @@ in
type = types.listOf types.str;
default = [];
description = ''
Include only files and directories matching the
specified patterns.
Include only files and directories matching these
patterns (the empty list includes everything).
Note that exclusions specified via
<literal>excludes</literal> take precedence over
inclusions.
Exclusions have precedence over inclusions.
'';
};
@ -156,10 +150,10 @@ in
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.
Reduce memory consumption by not caching small files.
Possibly beneficial if the average file size is smaller
than 1 MB and the number of files is lower than the
total amount of RAM in KB.
'';
};
@ -167,11 +161,9 @@ in
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.
Reduce memory consumption by a factor of 2 beyond what
<literal>lowmem</literal> does, at the cost of significantly
slowing down the archiving process.
'';
};
};
@ -188,25 +180,22 @@ in
gamedata =
{ directories = [ "/var/lib/minecraft "];
period = "*/30 * * * *";
period = "*:30";
};
}
'';
description = ''
Configuration of a Tarsnap archive. In the example, your
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
<literal>systemctl</literal>, using the
<literal>tarsnap@nixos</literal> or
<literal>tarsnap@gamedata</literal> units. For example,
<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,
down to second resolution. This means you can use GNU
<literal>sort</literal> to sort output easily.
Tarsnap archive configurations. Each attribute names an archive
to be created at a given time interval, according to the options
associated with it. When uploading to the tarsnap server,
archive names are suffixed by a 1 second resolution timestamp.
For each member of the set is created a timer which triggers the
instanced <literal>tarsnap@</literal> service unit. You may use
<command>systemctl start tarsnap@archive-name</command> to
manually trigger creation of <literal>archive-name</literal> at
any time.
'';
};
};
@ -216,38 +205,45 @@ in
assertions =
(mapAttrsToList (name: cfg:
{ assertion = cfg.directories != [];
message = "Must specify directories for Tarsnap to back up";
}) cfg.config) ++
message = "Must specify paths for tarsnap to back up";
}) cfg.archives) ++
(mapAttrsToList (name: cfg:
{ assertion = cfg.lowmem -> !cfg.verylowmem && (cfg.verylowmem -> !cfg.lowmem);
{ assertion = !(cfg.lowmem && cfg.verylowmem);
message = "You cannot set both lowmem and verylowmem";
}) cfg.config);
}) cfg.archives);
systemd.services."tarsnap@" = {
description = "Tarsnap Backup of '%i'";
description = "Tarsnap archive '%i'";
requires = [ "network.target" ];
path = [ pkgs.tarsnap pkgs.coreutils ];
scriptArgs = "%i";
script = ''
mkdir -p -m 0755 $(dirname ${cfg.cachedir})
mkdir -p -m 0600 ${cfg.cachedir}
mkdir -p -m 0755 ${dirOf cfg.cachedir}
mkdir -p -m 0700 ${cfg.cachedir}
DIRS=`cat /etc/tarsnap/$1.dirs`
exec tarsnap --configfile /etc/tarsnap/$1.conf -c -f $1-$(date +"%Y%m%d%H%M%S") $DIRS
'';
serviceConfig = {
IOSchedulingClass = "idle";
NoNewPrivileges = "true";
CapabilityBoundingSet = "CAP_DAC_READ_SEARCH";
};
};
services.cron.systemCronJobs = mapAttrsToList (name: cfg:
"${cfg.period} root ${config.systemd.package}/bin/systemctl start tarsnap@${name}"
) cfg.config;
systemd.timers = mapAttrs' (name: cfg: nameValuePair "tarsnap@${name}"
{ timerConfig.OnCalendar = cfg.period;
wantedBy = [ "timers.target" ];
}) cfg.archives;
environment.etc =
(mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.conf"
{ text = configFile cfg;
}) cfg.config) //
}) cfg.archives) //
(mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.dirs"
{ text = concatStringsSep " " cfg.directories;
}) cfg.config);
}) cfg.archives);
environment.systemPackages = [ pkgs.tarsnap ];
};