diff options
Diffstat (limited to 'modules/borgbackup/lvm-snapshots.nix')
-rw-r--r-- | modules/borgbackup/lvm-snapshots.nix | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/modules/borgbackup/lvm-snapshots.nix b/modules/borgbackup/lvm-snapshots.nix new file mode 100644 index 00000000..9b2a6562 --- /dev/null +++ b/modules/borgbackup/lvm-snapshots.nix | |||
@@ -0,0 +1,133 @@ | |||
1 | { config, lib, utils, pkgs, ... }: | ||
2 | |||
3 | with utils; | ||
4 | with lib; | ||
5 | |||
6 | let | ||
7 | cfg = config.services.lvm-snapshots; | ||
8 | |||
9 | snapshotMount = name: "${cfg.mountPoint}/${if isNull cfg.snapshots."${name}".mountName then name else cfg.snapshots."${name}".mountName}"; | ||
10 | snapshotName = name: "${name}-${cfg.mountSuffix}"; | ||
11 | |||
12 | snapshotConfig = { | ||
13 | options = { | ||
14 | LV = mkOption { | ||
15 | type = types.str; | ||
16 | }; | ||
17 | |||
18 | VG = mkOption { | ||
19 | type = types.str; | ||
20 | }; | ||
21 | |||
22 | mountName = mkOption { | ||
23 | type = types.nullOr types.str; | ||
24 | default = null; | ||
25 | }; | ||
26 | |||
27 | cowSize = mkOption { | ||
28 | type = types.str; | ||
29 | default = "-l20%ORIGIN"; | ||
30 | }; | ||
31 | |||
32 | readOnly = mkOption { | ||
33 | type = types.bool; | ||
34 | default = true; | ||
35 | }; | ||
36 | |||
37 | persist = mkOption { | ||
38 | type = types.bool; | ||
39 | default = false; | ||
40 | }; | ||
41 | }; | ||
42 | }; | ||
43 | in { | ||
44 | options = { | ||
45 | |||
46 | services.lvm-snapshots = { | ||
47 | snapshots = mkOption { | ||
48 | type = types.attrsOf (types.submodule snapshotConfig); | ||
49 | default = {}; | ||
50 | }; | ||
51 | |||
52 | mountPoint = mkOption { | ||
53 | type = types.path; | ||
54 | default = "/mnt"; | ||
55 | }; | ||
56 | |||
57 | mountSuffix = mkOption { | ||
58 | type = types.str; | ||
59 | default = "-snapshot"; | ||
60 | }; | ||
61 | }; | ||
62 | }; | ||
63 | |||
64 | |||
65 | config = mkIf (cfg != {}) { | ||
66 | |||
67 | boot.kernelModules = [ "dm_snapshot" ]; | ||
68 | |||
69 | # system.activationScripts = mapAttrs' (name: scfg: nameValuePair ("lvm-mountpoint" + name) '' | ||
70 | # mkdir -p ${snapshotMount name} | ||
71 | # '') cfg.snapshots; | ||
72 | |||
73 | systemd.services = mapAttrs' (name: scfg: nameValuePair ("lvm-snapshot@" + escapeSystemdPath name) { | ||
74 | enable = true; | ||
75 | |||
76 | description = "LVM-snapshot of ${scfg.VG}/${scfg.LV}"; | ||
77 | |||
78 | bindsTo = ["${escapeSystemdPath "/dev/${scfg.VG}/${scfg.LV}"}.device"]; | ||
79 | after = ["${escapeSystemdPath "/dev/${scfg.VG}/${scfg.LV}"}.device"]; | ||
80 | |||
81 | unitConfig = { | ||
82 | StopWhenUnneeded = !scfg.persist; | ||
83 | AssertPathIsDirectory = "/var/lock"; | ||
84 | }; | ||
85 | |||
86 | path = with pkgs; [ devicemapper utillinux ]; | ||
87 | |||
88 | script = '' | ||
89 | ( | ||
90 | flock -xn -E 4 9 | ||
91 | if [[ "$?" -ne 0 ]]; then | ||
92 | exit $? | ||
93 | fi | ||
94 | |||
95 | lvcreate -s ${scfg.cowSize} --name ${snapshotName name} ${scfg.VG}/${scfg.LV} | ||
96 | |||
97 | sleep infinity & | ||
98 | ) 9>/var/lock/lvm-snapshot.${scfg.VG} | ||
99 | ''; | ||
100 | |||
101 | preStart = '' | ||
102 | lvremove -f ${scfg.VG}/${snapshotName name} | ||
103 | ''; | ||
104 | |||
105 | preStop = '' | ||
106 | lvremove -f ${scfg.VG}/${snapshotName name} | ||
107 | ''; | ||
108 | |||
109 | serviceConfig = with pkgs; { | ||
110 | Type = "forking"; | ||
111 | RestartForceExitStatus = [ "4" ]; | ||
112 | RestartSec = "5min"; | ||
113 | }; | ||
114 | }) cfg.snapshots; | ||
115 | |||
116 | systemd.mounts = mapAttrsToList (name: scfg: { | ||
117 | enable = true; | ||
118 | |||
119 | unitConfig = { | ||
120 | # AssertPathIsDirectory = snapshotMount name; | ||
121 | StopWhenUnneeded = !scfg.persist; | ||
122 | }; | ||
123 | |||
124 | bindsTo = [ ("lvm-snapshot@" + escapeSystemdPath name + ".service") ]; | ||
125 | after = [ ("lvm-snapshot@" + escapeSystemdPath name + ".service") ]; | ||
126 | |||
127 | options = concatStringsSep "," ([ "noauto" ] ++ optional scfg.readOnly "ro"); | ||
128 | |||
129 | where = snapshotMount name; | ||
130 | what = "/dev/" + scfg.VG + "/" + snapshotName name; | ||
131 | }) cfg.snapshots; | ||
132 | }; | ||
133 | } | ||