about summary refs log tree commit diff
path: root/nixos/modules/services/backup/tarsnap.nix
diff options
context:
space:
mode:
authorAustin Seipp <aseipp@pobox.com>2014-04-28 18:15:14 -0500
committerAustin Seipp <aseipp@pobox.com>2014-04-28 18:15:16 -0500
commit9242ed1fe297daf144fd4034af95d4fb0f0e3fa9 (patch)
tree2623212e8c62dea63d06841b9bd05b15704e5cda /nixos/modules/services/backup/tarsnap.nix
parent7faaa9e6daa79f40ae3725e97c463746d079f3ae (diff)
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>
Diffstat (limited to 'nixos/modules/services/backup/tarsnap.nix')
-rw-r--r--nixos/modules/services/backup/tarsnap.nix310
1 files changed, 180 insertions, 130 deletions
diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix
index 1966242e3dcbc..1b0bcadca1515 100644
--- a/nixos/modules/services/backup/tarsnap.nix
+++ b/nixos/modules/services/backup/tarsnap.nix
@@ -7,9 +7,9 @@ let
 
   optionalNullStr = e: v: if e == null then "" else v;
 
-  configFile = pkgs.writeText "tarsnap.conf" ''
-    cachedir ${cfg.cachedir}
-    keyfile  ${cfg.keyfile}
+  configFile = cfg: ''
+    cachedir ${config.services.tarsnap.cachedir}
+    keyfile  ${config.services.tarsnap.keyfile}
     ${optionalString cfg.nodump "nodump"}
     ${optionalString cfg.printStats "print-stats"}
     ${optionalNullStr cfg.checkpointBytes "checkpoint-bytes "+cfg.checkpointBytes}
@@ -39,138 +39,174 @@ in
         '';
       };
 
-      label = mkOption {
-        type = types.str;
-        default = "nixos";
-        description = ''
-          Specifies the label for archives created by Tarsnap. The
-          full name will be
-          <literal>label-$(date+"%Y%m%d%H%M%S")</literal>. For
-          example, by default your backups will look similar to
-          <literal>nixos-20140301011501</literal>.
-        '';
-      };
-
-      cachedir = mkOption {
-        type    = 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.
-        '';
-      };
-
       keyfile = mkOption {
         type = types.path;
         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.
-        '';
-      };
-
-      nodump = mkOption {
-        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.
+          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.
         '';
       };
 
-      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 = [];
+      cachedir = mkOption {
+        type    = types.path;
+        default = "/var/cache/tarsnap";
         description = ''
-          Include only files and directories matching the specified patterns.
-
-          Note that exclusions specified via
-          <literal>excludes</literal> take precedence over inclusions.
+          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.
         '';
       };
 
-      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.
+      config = mkOption {
+        type = types.attrsOf (types.submodule (
+          {
+            options = {
+              nodump = mkOption {
+                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.
+                '';
+              };
+
+              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 * * * *";
+              };
+          }
         '';
-      };
 
-      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.
+          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.
         '';
       };
     };
@@ -178,26 +214,40 @@ in
 
   config = mkIf cfg.enable {
     assertions =
-      [ { assertion = cfg.directories != [];
+      (mapAttrsToList (name: cfg:
+        { assertion = cfg.directories != [];
           message = "Must specify directories for Tarsnap to back up";
-        }
+        }) cfg.config) ++
+      (mapAttrsToList (name: cfg:
         { assertion = cfg.lowmem -> !cfg.verylowmem && (cfg.verylowmem -> !cfg.lowmem);
           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 ];
+      scriptArgs = "%i";
       script = ''
         mkdir -p -m 0755 $(dirname ${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
-      "${cfg.period} root ${config.systemd.package}/bin/systemctl start tarsnap-backup.service";
+    services.cron.systemCronJobs = mapAttrsToList (name: cfg:
+      "${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 ];
   };