Skip to content

Commit f348bf1

Browse files
galin-sPetarKirov
authored andcommitted
feat(modules/mcl-disko): Create ZFS configuration module
1 parent d45bfb0 commit f348bf1

File tree

5 files changed

+436
-0
lines changed

5 files changed

+436
-0
lines changed

modules/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
./random-alerts
88
./host-info.nix
99
./secrets.nix
10+
./mcl-disko
1011
];
1112
}

modules/mcl-disko/default.nix

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
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+
disksNames = mkOption {
54+
type = types.listOf types.str;
55+
default = cfg.disks;
56+
example = [
57+
"sda"
58+
"sdb"
59+
"sdc"
60+
];
61+
description = "The disk partitions names to be used when ZFS is being created";
62+
};
63+
64+
zpool = {
65+
name = mkOption {
66+
type = types.str;
67+
default = "zfs_root";
68+
description = "The name of the ZFS Pool";
69+
};
70+
71+
mode = mkOption {
72+
type = types.enum [
73+
"stripe"
74+
"mirror"
75+
"raidz1"
76+
"raidz2"
77+
"raidz3"
78+
];
79+
default = "stripe";
80+
description = "Set ZFS Pool redundancy - e.g. 'mirror', 'raidz1', etc.";
81+
};
82+
83+
extraDatasets = mkOption {
84+
type = types.attrsOf (
85+
types.submodule (
86+
{ name, ... }:
87+
{
88+
options = {
89+
mountpoint = mkOption {
90+
type = types.nullOr types.str;
91+
default = name;
92+
example = "/var/lib";
93+
description = "The ZFS dataset mountpoint";
94+
};
95+
96+
type = mkOption {
97+
type = types.enum [
98+
"zfs_fs"
99+
"zfs_volume"
100+
];
101+
default = "zfs_fs";
102+
description = "Type of ZFS dataset";
103+
};
104+
105+
options = mkOption {
106+
type = types.attrs;
107+
default = { };
108+
example = {
109+
refreservation = "50G";
110+
};
111+
description = "";
112+
};
113+
114+
snapshot = mkEnableOption "Whether to enable ZFS snapshots";
115+
116+
refreservation = mkOption {
117+
type = types.nullOr types.str;
118+
default = null;
119+
description = "Size of reservations";
120+
};
121+
};
122+
}
123+
)
124+
);
125+
default = { };
126+
example = {
127+
"/opt".snapshot = false;
128+
"/opt/downloads".snapshot = false;
129+
"/opt/downloads/vm-images" = {
130+
snapshot = false;
131+
options = {
132+
quota = "120G";
133+
};
134+
};
135+
};
136+
description = "Extra ZFS Pool datasets";
137+
};
138+
};
139+
};
140+
141+
config.disko =
142+
let
143+
makePrimaryZfsDisk = import ./primaryZfsPartition.nix;
144+
makeSecondaryZfsDisk = import ./secondaryZfsPartition.nix;
145+
146+
first = builtins.head cfg.disks;
147+
rest = builtins.tail cfg.disks;
148+
149+
firstDiskName = builtins.head cfg.disksNames;
150+
restDisksNames = builtins.tail cfg.disksNames;
151+
152+
secondaryDisks = builtins.listToAttrs (
153+
lib.zipListsWith (disk: diskName: {
154+
name = diskName;
155+
value =
156+
if cfg.zpool.mode != "stripe" then
157+
makePrimaryZfsDisk {
158+
inherit disk lib;
159+
isSecondary = true;
160+
espSize = cfg.espSize;
161+
swapSize = cfg.swapSize;
162+
legacyBoot = cfg.legacyBoot;
163+
poolName = cfg.zpool.name;
164+
}
165+
else
166+
makeSecondaryZfsDisk {
167+
poolName = cfg.zpool.name;
168+
inherit disk lib;
169+
};
170+
}) rest restDisksNames
171+
);
172+
173+
in
174+
lib.mkIf cfg.enable {
175+
devices = {
176+
disk = secondaryDisks // {
177+
"${firstDiskName}" = makePrimaryZfsDisk {
178+
inherit lib;
179+
disk = first;
180+
isSecondary = false;
181+
espSize = cfg.espSize;
182+
swapSize = cfg.swapSize;
183+
legacyBoot = cfg.legacyBoot;
184+
poolName = cfg.zpool.name;
185+
};
186+
};
187+
zpool = import ./zpool.nix {
188+
poolName = cfg.zpool.name;
189+
poolMode = cfg.zpool.mode;
190+
poolExtraDatasets = cfg.zpool.extraDatasets;
191+
inherit lib;
192+
};
193+
};
194+
};
195+
};
196+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
{
2+
lib,
3+
disk,
4+
isSecondary,
5+
espSize,
6+
swapSize,
7+
legacyBoot,
8+
poolName,
9+
}:
10+
{
11+
type = "disk";
12+
device = disk;
13+
content =
14+
{
15+
type = if legacyBoot then "table" else "gpt";
16+
partitions =
17+
if !legacyBoot then
18+
{
19+
"ESP" = {
20+
device = "${disk}-part1";
21+
size = espSize;
22+
type = "EF00";
23+
content = {
24+
type = "filesystem";
25+
format = "vfat";
26+
mountpoint = if isSecondary then null else "/boot";
27+
mountOptions = [ "umask=0077" ];
28+
};
29+
};
30+
31+
"zfs" = {
32+
device = "${disk}-part2";
33+
end = "-${swapSize}";
34+
type = "BF00";
35+
content = {
36+
type = "zfs";
37+
pool = "${poolName}";
38+
};
39+
};
40+
41+
"swap" = {
42+
device = "${disk}-part3";
43+
size = swapSize;
44+
content = {
45+
type = "swap";
46+
randomEncryption = true;
47+
};
48+
};
49+
}
50+
else
51+
[
52+
{
53+
name = "boot";
54+
start = "1MiB";
55+
end = "2MiB";
56+
part-type = "primary";
57+
flags = [ "bios_grub" ];
58+
}
59+
{
60+
name = "ESP";
61+
start = "2MiB";
62+
end = espSize;
63+
bootable = true;
64+
content = {
65+
type = "filesystem";
66+
format = "vfat";
67+
mountpoint = if isSecondary then null else "/boot";
68+
};
69+
}
70+
{
71+
name = "zfs";
72+
start = espSize;
73+
end = "-${swapSize}";
74+
part-type = "primary";
75+
content = {
76+
type = "zfs";
77+
pool = "${poolName}";
78+
};
79+
}
80+
{
81+
name = "swap";
82+
start = "-${swapSize}";
83+
end = "100%";
84+
part-type = "primary";
85+
content = {
86+
type = "swap";
87+
randomEncryption = true;
88+
};
89+
}
90+
];
91+
}
92+
// lib.optionalAttrs legacyBoot {
93+
format = "gpt";
94+
};
95+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
lib,
3+
poolName,
4+
disk,
5+
}:
6+
{
7+
type = "disk";
8+
device = disk;
9+
content = {
10+
type = "gpt";
11+
partitions = {
12+
zfs = {
13+
device = "${disk}-part1";
14+
size = "100%";
15+
content = {
16+
type = "zfs";
17+
pool = "${poolName}";
18+
};
19+
};
20+
};
21+
};
22+
}

0 commit comments

Comments
 (0)