···
1
+
{ config, lib, pkgs, ... }:
5
+
let cfg = config.snapraid;
8
+
options.snapraid = with types; {
9
+
enable = mkEnableOption "SnapRAID";
10
+
dataDisks = mkOption {
17
+
description = "SnapRAID data disks.";
20
+
parityFiles = mkOption {
23
+
"/mnt/diskp/snapraid.parity"
24
+
"/mnt/diskq/snapraid.2-parity"
25
+
"/mnt/diskr/snapraid.3-parity"
26
+
"/mnt/disks/snapraid.4-parity"
27
+
"/mnt/diskt/snapraid.5-parity"
28
+
"/mnt/disku/snapraid.6-parity"
30
+
description = "SnapRAID parity files.";
33
+
contentFiles = mkOption {
36
+
"/var/snapraid.content"
37
+
"/mnt/disk1/snapraid.content"
38
+
"/mnt/disk2/snapraid.content"
40
+
description = "SnapRAID content list files.";
43
+
exclude = mkOption {
45
+
example = [ "*.unrecoverable" "/tmp/" "/lost+found/" ];
46
+
description = "SnapRAID exclude directives.";
49
+
touchBeforeSync = mkOption {
53
+
"Whether <command>snapraid touch</command> should be run before <command>snapraid sync</command>.";
56
+
sync.interval = mkOption {
59
+
description = "How often to run <command>snapraid sync</command>.";
63
+
interval = mkOption {
64
+
default = "Mon *-*-* 02:00:00";
66
+
description = "How often to run <command>snapraid scrub</command>.";
73
+
"Percent of the array that should be checked by <command>snapraid scrub</command>.";
76
+
olderThan = mkOption {
80
+
"Number of days since data was last scrubbed before it can be scrubbed again.";
84
+
extraConfig = mkOption {
93
+
description = "Extra config options for SnapRAID.";
100
+
nParity = builtins.length cfg.parityFiles;
101
+
mkPrepend = pre: s: pre + s;
106
+
assertion = nParity <= 6;
107
+
message = "You can have no more than six SnapRAID parity files.";
110
+
assertion = builtins.length cfg.contentFiles >= nParity + 1;
112
+
"There must be at least one SnapRAID content file for each SnapRAID parity file plus one.";
117
+
systemPackages = with pkgs; [ snapraid ];
119
+
etc."snapraid.conf" = {
122
+
prependData = mkPrepend "data ";
123
+
prependContent = mkPrepend "content ";
124
+
prependExclude = mkPrepend "exclude ";
126
+
concatStringsSep "\n"
128
+
((mapAttrsToList (name: value: name + " " + value)) dataDisks)
129
+
++ zipListsWith (a: b: a + b)
130
+
([ "parity " ] ++ map (i: toString i + "-parity ") (range 2 6))
131
+
parityFiles ++ map prependContent contentFiles
132
+
++ map prependExclude exclude) + "\n" + extraConfig;
136
+
systemd.services = with cfg; {
138
+
description = "Scrub the SnapRAID array";
139
+
startAt = scrub.interval;
142
+
ExecStart = "${pkgs.snapraid}/bin/snapraid scrub -p ${
143
+
toString scrub.plan
144
+
} -o ${toString scrub.olderThan}";
146
+
IOSchedulingPriority = 7;
147
+
CPUSchedulingPolicy = "batch";
149
+
LockPersonality = true;
150
+
MemoryDenyWriteExecute = true;
151
+
NoNewPrivileges = true;
152
+
PrivateDevices = true;
154
+
ProtectClock = true;
155
+
ProtectControlGroups = true;
156
+
ProtectHostname = true;
157
+
ProtectKernelLogs = true;
158
+
ProtectKernelModules = true;
159
+
ProtectKernelTunables = true;
160
+
RestrictAddressFamilies = "none";
161
+
RestrictNamespaces = true;
162
+
RestrictRealtime = true;
163
+
RestrictSUIDSGID = true;
164
+
SystemCallArchitectures = "native";
165
+
SystemCallFilter = "@system-service";
166
+
SystemCallErrorNumber = "EPERM";
167
+
CapabilityBoundingSet = "CAP_DAC_OVERRIDE";
169
+
ProtectSystem = "strict";
170
+
ProtectHome = "read-only";
172
+
# scrub requires access to directories containing content files
173
+
# to remove them if they are stale
175
+
contentDirs = map dirOf contentFiles;
178
+
attrValues dataDisks ++ contentDirs
181
+
unitConfig.After = "snapraid-sync.service";
184
+
description = "Synchronize the state of the SnapRAID array";
185
+
startAt = sync.interval;
188
+
ExecStart = "${pkgs.snapraid}/bin/snapraid sync";
190
+
IOSchedulingPriority = 7;
191
+
CPUSchedulingPolicy = "batch";
193
+
LockPersonality = true;
194
+
MemoryDenyWriteExecute = true;
195
+
NoNewPrivileges = true;
196
+
PrivateDevices = true;
198
+
ProtectClock = true;
199
+
ProtectControlGroups = true;
200
+
ProtectHostname = true;
201
+
ProtectKernelLogs = true;
202
+
ProtectKernelModules = true;
203
+
ProtectKernelTunables = true;
204
+
RestrictAddressFamilies = "none";
205
+
RestrictNamespaces = true;
206
+
RestrictRealtime = true;
207
+
RestrictSUIDSGID = true;
208
+
SystemCallArchitectures = "native";
209
+
SystemCallFilter = "@system-service";
210
+
SystemCallErrorNumber = "EPERM";
211
+
CapabilityBoundingSet = "CAP_DAC_OVERRIDE";
213
+
ProtectSystem = "strict";
214
+
ProtectHome = "read-only";
216
+
# sync requires access to directories containing content files
217
+
# to remove them if they are stale
219
+
contentDirs = map dirOf contentFiles;
222
+
attrValues dataDisks ++ parityFiles ++ contentDirs
224
+
} // optionalAttrs touchBeforeSync {
225
+
ExecStartPre = "${pkgs.snapraid}/bin/snapraid touch";