Skip to content

Commit 6b33832

Browse files
committed
feat(modules/mcl-disko): Create ZFS configuration module
1 parent c3d851e commit 6b33832

File tree

5 files changed

+348
-0
lines changed

5 files changed

+348
-0
lines changed

modules/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
./pyroscope
66
./folder-size-metrics
77
./shard-split
8+
./mcl-disko
89
];
910
}

modules/mcl-disko/default.nix

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
{ withSystem, inputs, ... }:
2+
{
3+
flake.modules.nixos.mcl-disko =
4+
{
5+
pkgs,
6+
config,
7+
lib,
8+
...
9+
}:
10+
with lib;
11+
let
12+
cfg = config.mcl.disko;
13+
in
14+
{
15+
imports = [
16+
inputs.disko.nixosModules.disko
17+
];
18+
options.mcl.disko = {
19+
enable = mkEnableOption "Enable Module";
20+
21+
legacyBoot = mkOption {
22+
type = types.bool;
23+
default = false;
24+
example = true;
25+
description = "Declare if the configuration is for a Hetzner server or not";
26+
};
27+
28+
swapSize = mkOption {
29+
type = types.str;
30+
default = "32G";
31+
example = "32768M";
32+
description = "The size of the hard disk space used when RAM is full";
33+
};
34+
35+
espSize = mkOption {
36+
type = types.str;
37+
default = "4G";
38+
example = "4096M";
39+
description = "The size of the hard disk space used for the ESP filesystem";
40+
};
41+
42+
disks = mkOption {
43+
type = types.listOf types.str;
44+
default = [ ];
45+
example = [
46+
"/dev/disk/sda"
47+
"/dev/disk/sdb"
48+
"/dev/disk/sdc"
49+
];
50+
description = "The disk partitions to be used when ZFS is being created";
51+
};
52+
53+
zpool = {
54+
name = mkOption {
55+
type = types.str;
56+
default = "zfs_root";
57+
description = "The name of the ZFS Pool";
58+
};
59+
60+
mode = mkOption {
61+
type = types.enum [
62+
"stripe"
63+
"mirror"
64+
"raidz1"
65+
"raidz2"
66+
"raidz3"
67+
];
68+
default = "stripe";
69+
description = "Set ZFS Pool redundancy - e.g. 'mirror', 'raidz1', etc.";
70+
};
71+
72+
extraDatasets = mkOption {
73+
type = types.attrsOf (
74+
types.submodule (
75+
{ name, ... }:
76+
{
77+
options = {
78+
mountpoint = mkOption {
79+
type = types.nullOr types.str;
80+
default = name;
81+
example = "/var/lib";
82+
description = "The ZFS dataset mountpoint";
83+
};
84+
85+
type = mkOption {
86+
type = types.enum [
87+
"zfs_fs"
88+
"zfs_volume"
89+
];
90+
default = "zfs_fs";
91+
description = "Type of ZFS dataset";
92+
};
93+
snapshot = mkEnableOption "Whether to enable ZFS snapshots";
94+
};
95+
96+
}
97+
)
98+
);
99+
default = { };
100+
example = {
101+
"/opt".snapshot = false;
102+
"/opt/downloads".snapshot = false;
103+
"/opt/downloads/vm-images" = {
104+
snapshot = false;
105+
options = {
106+
quota = "120G";
107+
};
108+
};
109+
};
110+
description = "Extra ZFS Pool datasets";
111+
};
112+
};
113+
};
114+
115+
config.disko =
116+
let
117+
makePrimaryZfsDisk = import ./primaryZfsPartition.nix;
118+
makeSecondaryZfsDisk = import ./secondaryZfsPartition.nix;
119+
120+
first = builtins.head cfg.disks;
121+
rest = builtins.tail cfg.disks;
122+
secondaryDisks = builtins.listToAttrs (
123+
builtins.map (disk: {
124+
name = disk;
125+
value =
126+
if cfg.zpool.mode != "stripe" then
127+
makePrimaryZfsDisk {
128+
disk = first;
129+
espSize = cfg.espSize;
130+
swapSize = cfg.swapSize;
131+
legacyBoot = cfg.legacyBoot;
132+
poolName = cfg.zpool.name;
133+
}
134+
else
135+
makeSecondaryZfsDisk {
136+
poolName = cfg.zpool.name;
137+
inherit disk;
138+
};
139+
}) rest
140+
);
141+
in
142+
lib.mkIf cfg.enable {
143+
devices = {
144+
disk = secondaryDisks // {
145+
"${first}" = makePrimaryZfsDisk {
146+
disk = first;
147+
espSize = cfg.espSize;
148+
swapSize = cfg.swapSize;
149+
legacyBoot = cfg.legacyBoot;
150+
poolName = cfg.zpool.name;
151+
};
152+
};
153+
zpool = import ./zpool.nix {
154+
poolName = cfg.zpool.name;
155+
poolMode = cfg.zpool.mode;
156+
poolExtraDatasets = cfg.zpool.extraDatasets;
157+
inherit lib;
158+
};
159+
};
160+
};
161+
};
162+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
disk,
3+
espSize,
4+
swapSize,
5+
legacyBoot,
6+
poolName,
7+
}:
8+
{
9+
type = "disk";
10+
device = disk;
11+
content = {
12+
type = "gpt";
13+
partitions = {
14+
ESP = {
15+
device = "${disk}-part1";
16+
priority = 0;
17+
size = espSize;
18+
type = "EF00";
19+
content = {
20+
type = "filesystem";
21+
format = "vfat";
22+
mountpoint = "/boot";
23+
mountOptions = [ "umask=0077" ];
24+
};
25+
};
26+
27+
zfs = {
28+
device = "${disk}-part2";
29+
priority = 1;
30+
end = "-${swapSize}";
31+
type = "BF00";
32+
content = {
33+
type = "zfs";
34+
pool = "${poolName}";
35+
};
36+
};
37+
38+
swap = {
39+
device = "${disk}-part3";
40+
priority = 2;
41+
size = if legacyBoot == true then "100%" else swapSize;
42+
content = {
43+
type = "swap";
44+
randomEncryption = true;
45+
};
46+
};
47+
};
48+
};
49+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{ poolName, disk }:
2+
{
3+
type = "disk";
4+
device = disk;
5+
content = {
6+
type = "gpt";
7+
partitions = {
8+
zfs = {
9+
device = "${disk}-part1";
10+
size = "100%";
11+
content = {
12+
type = "zfs";
13+
pool = "${poolName}";
14+
};
15+
};
16+
};
17+
};
18+
}

modules/mcl-disko/zpool.nix

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
{
2+
lib,
3+
poolName,
4+
poolMode,
5+
poolExtraDatasets,
6+
}:
7+
let
8+
translateDataSetToDiskoConfig =
9+
dataset@{ snapshot, ... }:
10+
lib.recursiveUpdate dataset {
11+
type = "zfs_fs";
12+
options = {
13+
"com.sun:auto-snapshot" = if dataset.snapshot then "on" else "off";
14+
canmount = "on";
15+
};
16+
};
17+
18+
restructuredDatasets = builtins.mapAttrs (
19+
n: v: (builtins.removeAttrs (translateDataSetToDiskoConfig poolExtraDatasets.${n}) [ "snapshot" ])
20+
) poolExtraDatasets;
21+
in
22+
{
23+
${poolName} = {
24+
type = "zpool";
25+
mode = if poolMode == "stripe" then "" else poolMode;
26+
rootFsOptions = {
27+
acltype = "posixacl";
28+
atime = "off";
29+
canmount = "off";
30+
checksum = "sha512";
31+
compression = "lz4";
32+
xattr = "sa";
33+
mountpoint = "none";
34+
"com.sun:auto-snapshot" = "false";
35+
};
36+
options = {
37+
autotrim = "on";
38+
listsnapshots = "on";
39+
};
40+
41+
postCreateHook = "zfs snapshot ${poolName}@blank";
42+
43+
datasets = {
44+
root = {
45+
mountpoint = "/";
46+
type = "zfs_fs";
47+
options = {
48+
"com.sun:auto-snapshot" = "false";
49+
mountpoint = "legacy";
50+
};
51+
};
52+
53+
"root/nix" = {
54+
mountpoint = "/nix";
55+
type = "zfs_fs";
56+
options = {
57+
"com.sun:auto-snapshot" = "false";
58+
canmount = "on";
59+
mountpoint = "legacy";
60+
refreservation = "100GiB";
61+
};
62+
};
63+
64+
"root/var" = {
65+
mountpoint = "/var";
66+
type = "zfs_fs";
67+
options = {
68+
"com.sun:auto-snapshot" = "true";
69+
canmount = "on";
70+
mountpoint = "legacy";
71+
};
72+
};
73+
74+
"root/var/lib" = {
75+
mountpoint = "/var/lib";
76+
type = "zfs_fs";
77+
options = {
78+
"com.sun:auto-snapshot" = "true";
79+
canmount = "on";
80+
mountpoint = "legacy";
81+
};
82+
};
83+
84+
"root/home" = {
85+
mountpoint = "/home";
86+
type = "zfs_fs";
87+
options = {
88+
"com.sun:auto-snapshot" = "true";
89+
canmount = "on";
90+
mountpoint = "legacy";
91+
refreservation = "200GiB";
92+
};
93+
};
94+
95+
"root/var/lib/docker" = {
96+
mountpoint = "/var/lib/docker";
97+
type = "zfs_fs";
98+
options = {
99+
"com.sun:auto-snapshot" = "false";
100+
canmount = "on";
101+
mountpoint = "legacy";
102+
refreservation = "100GiB";
103+
};
104+
};
105+
106+
"root/var/lib/containers" = {
107+
mountpoint = "/var/lib/containers";
108+
type = "zfs_fs";
109+
options = {
110+
"com.sun:auto-snapshot" = "false";
111+
canmount = "on";
112+
mountpoint = "legacy";
113+
refreservation = "100GiB";
114+
};
115+
};
116+
} // restructuredDatasets;
117+
};
118+
}

0 commit comments

Comments
 (0)