]> Git — Sourcephile - sourcephile-nix.git/blob - nixos/modules/services/backup/syncoid.nix
wireguard: setup external vpn
[sourcephile-nix.git] / nixos / modules / services / backup / syncoid.nix
1 { config, lib, pkgs, ... }:
2
3 with lib;
4
5 let
6 cfg = config.services.syncoid;
7 # Escape as required by: https://www.freedesktop.org/software/systemd/man/systemd.unit.html
8 escapeUnitName = name:
9 lib.concatMapStrings (s: if lib.isList s then "-" else s)
10 (builtins.split "[^a-zA-Z0-9_.\\-]+" name);
11 in {
12
13 # Interface
14
15 options.services.syncoid = {
16 enable = mkEnableOption "Syncoid ZFS synchronization service";
17
18 interval = mkOption {
19 type = types.str;
20 default = "hourly";
21 example = "*-*-* *:15:00";
22 description = ''
23 Run syncoid at this interval. The default is to run hourly.
24
25 The format is described in
26 <citerefentry><refentrytitle>systemd.time</refentrytitle>
27 <manvolnum>7</manvolnum></citerefentry>.
28 '';
29 };
30
31 user = mkOption {
32 type = types.str;
33 default = "root";
34 example = "backup";
35 description = ''
36 The user for the service. Sudo or ZFS privilege delegation must be
37 configured to use a user other than root.
38 '';
39 };
40
41 sshKey = mkOption {
42 type = types.nullOr types.path;
43 # Prevent key from being copied to store
44 apply = mapNullable toString;
45 default = null;
46 description = ''
47 SSH private key file to use to login to the remote system. Can be
48 overridden in individual commands.
49 '';
50 };
51
52 commonArgs = mkOption {
53 type = types.listOf types.str;
54 default = [];
55 example = [ "--no-sync-snap" ];
56 description = ''
57 Arguments to add to every syncoid command, unless disabled for that
58 command. See
59 <link xlink:href="https://github.com/jimsalterjrs/sanoid/#syncoid-command-line-options"/>
60 for available options.
61 '';
62 };
63
64 service = mkOption {
65 type = types.attrs;
66 default = {};
67 description = ''
68 Systemd configuration common to all syncoid services.
69 '';
70 };
71
72 commands = mkOption {
73 type = types.attrsOf (types.submodule ({ name, ... }: {
74 options = {
75 source = mkOption {
76 type = types.str;
77 example = "pool/dataset";
78 description = ''
79 Source ZFS dataset. Can be either local or remote. Defaults to
80 the attribute name.
81 '';
82 };
83
84 target = mkOption {
85 type = types.str;
86 example = "user@server:pool/dataset";
87 description = ''
88 Target ZFS dataset. Can be either local
89 (<replaceable>pool/dataset</replaceable>) or remote
90 (<replaceable>user@server:pool/dataset</replaceable>).
91 '';
92 };
93
94 recursive = mkEnableOption ''the transfer of child datasets'';
95
96 sshKey = mkOption {
97 type = types.nullOr types.path;
98 # Prevent key from being copied to store
99 apply = mapNullable toString;
100 description = ''
101 SSH private key file to use to login to the remote system.
102 Defaults to <option>services.syncoid.sshKey</option> option.
103 '';
104 };
105
106 sendOptions = mkOption {
107 type = types.separatedString " ";
108 default = "";
109 example = "Lc e";
110 description = ''
111 Advanced options to pass to zfs send. Options are specified
112 without their leading dashes and separated by spaces.
113 '';
114 };
115
116 recvOptions = mkOption {
117 type = types.separatedString " ";
118 default = "";
119 example = "ux recordsize o compression=lz4";
120 description = ''
121 Advanced options to pass to zfs recv. Options are specified
122 without their leading dashes and separated by spaces.
123 '';
124 };
125
126 useCommonArgs = mkOption {
127 type = types.bool;
128 default = true;
129 description = ''
130 Whether to add the configured common arguments to this command.
131 '';
132 };
133
134 service = mkOption {
135 type = types.attrs;
136 default = {};
137 description = ''
138 Systemd configuration specific to this syncoid service.
139 '';
140 };
141
142 extraArgs = mkOption {
143 type = types.listOf types.str;
144 default = [];
145 example = [ "--sshport 2222" ];
146 description = "Extra syncoid arguments for this command.";
147 };
148 };
149 config = {
150 source = mkDefault name;
151 sshKey = mkDefault cfg.sshKey;
152 };
153 }));
154 default = {};
155 example."pool/test".target = "root@target:pool/test";
156 description = "Syncoid commands to run.";
157 };
158 };
159
160 # Implementation
161
162 config = mkIf cfg.enable {
163 systemd.services = mapAttrs' (name: c:
164 nameValuePair "syncoid-${escapeUnitName name}" (recursiveUpdate (recursiveUpdate {
165 description = "Syncoid ZFS synchronization from ${c.source} to ${c.target}";
166 script = lib.escapeShellArgs ([ "${pkgs.sanoid}/bin/syncoid" ]
167 ++ (optionals c.useCommonArgs cfg.commonArgs)
168 ++ (optional c.recursive "-r")
169 ++ (optionals (c.sshKey != null) [ "--sshkey" c.sshKey ])
170 ++ c.extraArgs
171 ++ [ "--sendoptions" c.sendOptions
172 "--recvoptions" c.recvOptions
173 c.source c.target
174 ]);
175 after = [ "zfs.target" ];
176 serviceConfig.User = cfg.user;
177 startAt = cfg.interval;
178 } cfg.serviceConfig) c.serviceConfig) cfg.commands;
179 };
180
181 meta.maintainers = with maintainers; [ lopsided98 ];
182 }