git.iko.soy/typeable/nixpkgs
on master help sign in
Merge pull request #127245 from lunik1/snapraid-module

nixos/snapraid: init

commitb466d6c702867f6a3844db58dd4da6298a1df25c authorRyan Mulligan <ryan@ryantm.com> dateWed 14 Jul 2021, 13:07 (5 years ago) parentcd4d162145a3d0
4 files changed+242
nixos/doc/manual/from_md/release-notes/rl-2111.section.xml+7 nixos/doc/manual/release-notes/rl-2111.section.md+4 nixos/modules/module-list.nix+1 nixos/modules/tasks/snapraid.nix+230
nixos/doc/manual/from_md/release-notes/rl-2111.section.xml+7
@@ -78,6 +78,13 @@
7878 <link linkend="opt-services.vikunja.enable">services.vikunja</link>.
7979 </para>
8080 </listitem>
81+ <listitem>
82+ <para>
83+ <link xlink:href="https://www.snapraid.it/">snapraid</link>, a
84+ backup program for disk arrays. Available as
85+ <link linkend="opt-snapraid.enable">snapraid</link>.
86+ </para>
87+ </listitem>
8188 </itemizedlist>
8289 </section>
8390 <section xml:id="sec-release-21.11-incompatibilities">
nixos/doc/manual/release-notes/rl-2111.section.md+4
@@ -23,6 +23,10 @@ In addition to numerous new and upgraded packages, this release has the followin
2323
2424- [vikunja](https://vikunja.io), a to-do list app. Available as [services.vikunja](#opt-services.vikunja.enable).
2525
26+- [snapraid](https://www.snapraid.it/), a backup program for disk arrays.
27+ Available as [snapraid](#opt-snapraid.enable).
28+
29+
2630## Backward Incompatibilities {#sec-release-21.11-incompatibilities}
2731
2832- The `staticjinja` package has been upgraded from 1.0.4 to 3.0.1
nixos/modules/module-list.nix+1
@@ -1104,6 +1104,7 @@
11041104 ./tasks/network-interfaces-systemd.nix
11051105 ./tasks/network-interfaces-scripted.nix
11061106 ./tasks/scsi-link-power-management.nix
1107+ ./tasks/snapraid.nix
11071108 ./tasks/swraid.nix
11081109 ./tasks/trackpoint.nix
11091110 ./tasks/powertop.nix
nixos/modules/tasks/snapraid.nixnew file+230
@@ -0,0 +1,230 @@
1+{ config, lib, pkgs, ... }:
2+
3+with lib;
4+
5+let cfg = config.snapraid;
6+in
7+{
8+ options.snapraid = with types; {
9+ enable = mkEnableOption "SnapRAID";
10+ dataDisks = mkOption {
11+ default = { };
12+ example = {
13+ d1 = "/mnt/disk1/";
14+ d2 = "/mnt/disk2/";
15+ d3 = "/mnt/disk3/";
16+ };
17+ description = "SnapRAID data disks.";
18+ type = attrsOf str;
19+ };
20+ parityFiles = mkOption {
21+ default = [ ];
22+ example = [
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"
29+ ];
30+ description = "SnapRAID parity files.";
31+ type = listOf str;
32+ };
33+ contentFiles = mkOption {
34+ default = [ ];
35+ example = [
36+ "/var/snapraid.content"
37+ "/mnt/disk1/snapraid.content"
38+ "/mnt/disk2/snapraid.content"
39+ ];
40+ description = "SnapRAID content list files.";
41+ type = listOf str;
42+ };
43+ exclude = mkOption {
44+ default = [ ];
45+ example = [ "*.unrecoverable" "/tmp/" "/lost+found/" ];
46+ description = "SnapRAID exclude directives.";
47+ type = listOf str;
48+ };
49+ touchBeforeSync = mkOption {
50+ default = true;
51+ example = false;
52+ description =
53+ "Whether <command>snapraid touch</command> should be run before <command>snapraid sync</command>.";
54+ type = bool;
55+ };
56+ sync.interval = mkOption {
57+ default = "01:00";
58+ example = "daily";
59+ description = "How often to run <command>snapraid sync</command>.";
60+ type = str;
61+ };
62+ scrub = {
63+ interval = mkOption {
64+ default = "Mon *-*-* 02:00:00";
65+ example = "weekly";
66+ description = "How often to run <command>snapraid scrub</command>.";
67+ type = str;
68+ };
69+ plan = mkOption {
70+ default = 8;
71+ example = 5;
72+ description =
73+ "Percent of the array that should be checked by <command>snapraid scrub</command>.";
74+ type = int;
75+ };
76+ olderThan = mkOption {
77+ default = 10;
78+ example = 20;
79+ description =
80+ "Number of days since data was last scrubbed before it can be scrubbed again.";
81+ type = int;
82+ };
83+ };
84+ extraConfig = mkOption {
85+ default = "";
86+ example = ''
87+ nohidden
88+ blocksize 256
89+ hashsize 16
90+ autosave 500
91+ pool /pool
92+ '';
93+ description = "Extra config options for SnapRAID.";
94+ type = lines;
95+ };
96+ };
97+
98+ config =
99+ let
100+ nParity = builtins.length cfg.parityFiles;
101+ mkPrepend = pre: s: pre + s;
102+ in
103+ mkIf cfg.enable {
104+ assertions = [
105+ {
106+ assertion = nParity <= 6;
107+ message = "You can have no more than six SnapRAID parity files.";
108+ }
109+ {
110+ assertion = builtins.length cfg.contentFiles >= nParity + 1;
111+ message =
112+ "There must be at least one SnapRAID content file for each SnapRAID parity file plus one.";
113+ }
114+ ];
115+
116+ environment = {
117+ systemPackages = with pkgs; [ snapraid ];
118+
119+ etc."snapraid.conf" = {
120+ text = with cfg;
121+ let
122+ prependData = mkPrepend "data ";
123+ prependContent = mkPrepend "content ";
124+ prependExclude = mkPrepend "exclude ";
125+ in
126+ concatStringsSep "\n"
127+ (map prependData
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;
133+ };
134+ };
135+
136+ systemd.services = with cfg; {
137+ snapraid-scrub = {
138+ description = "Scrub the SnapRAID array";
139+ startAt = scrub.interval;
140+ serviceConfig = {
141+ Type = "oneshot";
142+ ExecStart = "${pkgs.snapraid}/bin/snapraid scrub -p ${
143+ toString scrub.plan
144+ } -o ${toString scrub.olderThan}";
145+ Nice = 19;
146+ IOSchedulingPriority = 7;
147+ CPUSchedulingPolicy = "batch";
148+
149+ LockPersonality = true;
150+ MemoryDenyWriteExecute = true;
151+ NoNewPrivileges = true;
152+ PrivateDevices = true;
153+ PrivateTmp = 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";
168+
169+ ProtectSystem = "strict";
170+ ProtectHome = "read-only";
171+ ReadWritePaths =
172+ # scrub requires access to directories containing content files
173+ # to remove them if they are stale
174+ let
175+ contentDirs = map dirOf contentFiles;
176+ in
177+ unique (
178+ attrValues dataDisks ++ contentDirs
179+ );
180+ };
181+ unitConfig.After = "snapraid-sync.service";
182+ };
183+ snapraid-sync = {
184+ description = "Synchronize the state of the SnapRAID array";
185+ startAt = sync.interval;
186+ serviceConfig = {
187+ Type = "oneshot";
188+ ExecStart = "${pkgs.snapraid}/bin/snapraid sync";
189+ Nice = 19;
190+ IOSchedulingPriority = 7;
191+ CPUSchedulingPolicy = "batch";
192+
193+ LockPersonality = true;
194+ MemoryDenyWriteExecute = true;
195+ NoNewPrivileges = true;
196+ PrivateDevices = true;
197+ PrivateTmp = 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";
212+
213+ ProtectSystem = "strict";
214+ ProtectHome = "read-only";
215+ ReadWritePaths =
216+ # sync requires access to directories containing content files
217+ # to remove them if they are stale
218+ let
219+ contentDirs = map dirOf contentFiles;
220+ in
221+ unique (
222+ attrValues dataDisks ++ parityFiles ++ contentDirs
223+ );
224+ } // optionalAttrs touchBeforeSync {
225+ ExecStartPre = "${pkgs.snapraid}/bin/snapraid touch";
226+ };
227+ };
228+ };
229+ };
230+}