summary refs log tree commit diff
path: root/nixos/modules/services/backup/tarsnap.nix
blob: 03fbd29a191d11e52f456e423e5af4028daebddb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
{ config, pkgs, ... }:

with pkgs.lib;

let
  cfg = config.services.tarsnap;

  optionalNullStr = e: v: if e == null then "" else v;

  configFile = pkgs.writeText "tarsnap.conf" ''
    cachedir ${cfg.cachedir}
    keyfile  ${cfg.keyfile}
    ${optionalString cfg.nodump "nodump"}
    ${optionalString cfg.printStats "print-stats"}
    ${optionalNullStr cfg.checkpointBytes "checkpoint-bytes "+cfg.checkpointBytes}
    ${optionalString cfg.aggressiveNetworking "aggressive-networking"}
    ${concatStringsSep "\n" (map (v: "exclude "+v) cfg.excludes)}
    ${concatStringsSep "\n" (map (v: "include "+v) cfg.includes)}
    ${optionalString cfg.lowmem "lowmem"}
    ${optionalString cfg.verylowmem "verylowmem"}
  '';
in
{
  options = {
    services.tarsnap = {
      enable = mkOption {
        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 <link xlink:href='http://www.tarsnap.com/gettingstarted.html'>Getting Started</link> 
          Tarsnap page.
        '';
      };

      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-20140301021501</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.
        '';
      };

      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 update 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.
        '';
      };
    };
  };

  config = mkIf cfg.enable {
    assertions =
      [ { assertion = cfg.directories != [];
          message = "Must specify directories for Tarsnap to back up";
        }
        { assertion = cfg.lowmem -> !cfg.verylowmem && (cfg.verylowmem -> !cfg.lowmem);
          message = "You cannot set both lowmem and verylowmem";
        }
      ];

    systemd.services.tarsnap-backup = {
      description = "Tarsnap Backup process";
      path = [ pkgs.tarsnap pkgs.coreutils ];
      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}
      '';
    };

    services.cron.systemCronJobs = optional cfg.enable
      "${cfg.period} root ${config.systemd.package}/bin/systemctl start tarsnap-backup.service";

    environment.systemPackages = [ pkgs.tarsnap ];
  };
}