blob: d260e29dc0a11b23e94cb90a750e21fcade15818 (
plain)
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
|
{ config, pkgs, lib, ... }:
with lib;
with lib.types;
with builtins;
let
groups = filterAttrs (n: _: n != "_module") config.nixsap.system.lvm.raid0;
createLV = vg: lv: s: opts:
let
new = toString s;
stripes = toString opts.stripes;
sizeSpec = if opts.units == "%"
then "--extents ${new}%VG"
else "--size ${new}${opts.units}";
scale = {
"%" = "* 100 / $(vgs --unit b --noheadings --nosuffix --options vg_size ${vg})";
"M" = "/ ${toString (1000 * 1000)}";
"m" = "/ ${toString (1024 * 1024)}";
"G" = "/ ${toString (1000 * 1000 * 1000)}";
"g" = "/ ${toString (1024 * 1024 * 1024)}";
"T" = "/ ${toString (1000 * 1000 * 1000 * 1000)}";
"t" = "/ ${toString (1024 * 1024 * 1024 * 1024)}";
};
in pkgs.writeBashScript "raid0-create-${vg}-${lv}" ''
set -eu
device=/dev/${vg}/${lv}
lv_size=$(lvs --unit b --noheadings --nosuffix --options lv_size "$device" || echo 0)
old=$(( lv_size ${scale."${opts.units}"} ))
if (( ${new} == old )) ; then
exit 0
elif (( old == 0 )); then
lvcreate ${vg} --name ${lv} ${sizeSpec} --stripes ${stripes}
elif (( ${new} < old )) ; then
echo "Cannot shrink volume $device from $old ${opts.units} to ${new} ${opts.units}" >&2
exit 1
else
lvextend "$device" ${sizeSpec}
resize2fs "$device"
fi
'';
createVG = vg: pv: pkgs.writeBashScript "raid0-create-vg-${vg}" ''
set -eu
for pv in ${toString pv}; do
type=$(blkid -p -s TYPE -o value "$pv" || true)
if [ "$type" != LVM2_member ]; then
pvcreate "$pv"
if ! vgs ${vg}; then
vgcreate ${vg} "$pv"
else
vgextend ${vg} "$pv"
fi
fi
done
'';
mkRaidService = vg: opts:
let
ExecStart = pkgs.writeBashScript "raid0-${vg}" ''
set -eu
${createVG vg opts.physical}
${concatStringsSep "\n" (
mapAttrsToList (v: s:
"${createLV vg (baseNameOf v) s opts}")
opts.fileSystems
)}
vgchange -ay ${vg}
udevadm trigger --action=add
'';
in nameValuePair "raid0-${vg}" rec {
wantedBy = map (v: "dev-${vg}-${baseNameOf v}.device") (attrNames opts.fileSystems);
requires = map (pv: replaceStrings ["/"] ["-"] (removePrefix "/" pv) + ".device") opts.physical;
after = requires;
before = wantedBy;
unitConfig.DefaultDependencies = false;
path = with pkgs; [ utillinux lvm2 e2fsprogs ];
serviceConfig = {
inherit ExecStart;
RemainAfterExit = true;
Type = "oneshot";
};
};
in {
options.nixsap.system = {
lvm.raid0 = mkOption {
description = "Set of LVM2 volume groups";
default = {};
type = attrsOf (submodule {
options = {
stripes = mkOption {
description = "Number of stripes";
type = int;
example = 2;
};
physical = mkOption {
description = "List of physical devices (must be even for stripes)";
example = [ "/dev/sdb" "/dev/sdc" ];
type = listOf path;
};
fileSystems = mkOption {
description = "Filesystems and their sizes";
type = attrsOf int;
example = { "/mariadb/db" = 100; };
};
units = mkOption {
description = "Units of size";
type = enum [ "%" "m" "g" "t" "M" "G" "T"];
};
};
});
};
};
config = {
systemd.services = mapAttrs' mkRaidService groups;
fileSystems = foldl (a: b: a//b) {} (
mapAttrsToList (vg: opts: genAttrs (attrNames opts.fileSystems)
(fs: {
fsType = "ext4";
autoFormat = true;
device = "/dev/${vg}/${baseNameOf fs}";
})
) groups
);
};
}
|