1{
2 system ? builtins.currentSystem,
3 config ? { },
4 pkgs ? import ../.. { inherit system config; },
5}:
6
7with import ../lib/testing-python.nix { inherit system pkgs; };
8
9let
10
11 makeZfsTest =
12 {
13 kernelPackages,
14 enableSystemdStage1 ? false,
15 zfsPackage,
16 extraTest ? "",
17 }:
18 makeTest {
19 name = zfsPackage.kernelModuleAttribute;
20 meta = with pkgs.lib.maintainers; {
21 maintainers = [ elvishjerricco ];
22 };
23
24 nodes.machine =
25 {
26 config,
27 pkgs,
28 lib,
29 ...
30 }:
31 let
32 usersharePath = "/var/lib/samba/usershares";
33 in
34 {
35 virtualisation = {
36 emptyDiskImages = [
37 4096
38 4096
39 ];
40 useBootLoader = true;
41 useEFIBoot = true;
42 };
43 boot.loader.systemd-boot.enable = true;
44 boot.loader.timeout = 0;
45 boot.loader.efi.canTouchEfiVariables = true;
46 networking.hostId = "deadbeef";
47 boot.kernelPackages = kernelPackages;
48 boot.zfs.package = zfsPackage;
49 boot.supportedFilesystems = [ "zfs" ];
50 boot.initrd.systemd.enable = enableSystemdStage1;
51
52 environment.systemPackages = [ pkgs.parted ];
53
54 # /dev/disk/by-id doesn't get populated in the NixOS test framework
55 boot.zfs.devNodes = "/dev/disk/by-uuid";
56
57 specialisation.samba.configuration = {
58 services.samba = {
59 enable = true;
60 settings.global = {
61 "registry shares" = true;
62 "usershare path" = "${usersharePath}";
63 "usershare allow guests" = true;
64 "usershare max shares" = "100";
65 "usershare owner only" = false;
66 };
67 };
68 systemd.services.samba-smbd.serviceConfig.ExecStartPre =
69 "${pkgs.coreutils}/bin/mkdir -m +t -p ${usersharePath}";
70 virtualisation.fileSystems = {
71 "/tmp/mnt" = {
72 device = "rpool/root";
73 fsType = "zfs";
74 };
75 };
76 };
77
78 specialisation.encryption.configuration = {
79 boot.zfs.requestEncryptionCredentials = [ "automatic" ];
80 virtualisation.fileSystems."/automatic" = {
81 device = "automatic";
82 fsType = "zfs";
83 };
84 virtualisation.fileSystems."/manual" = {
85 device = "manual";
86 fsType = "zfs";
87 };
88 virtualisation.fileSystems."/manual/encrypted" = {
89 device = "manual/encrypted";
90 fsType = "zfs";
91 options = [ "noauto" ];
92 };
93 virtualisation.fileSystems."/manual/httpkey" = {
94 device = "manual/httpkey";
95 fsType = "zfs";
96 options = [ "noauto" ];
97 };
98 };
99
100 specialisation.forcepool.configuration = {
101 systemd.services.zfs-import-forcepool.wantedBy = lib.mkVMOverride [ "forcepool.mount" ];
102 systemd.targets.zfs.wantedBy = lib.mkVMOverride [ ];
103 boot.zfs.forceImportAll = true;
104 virtualisation.fileSystems."/forcepool" = {
105 device = "forcepool";
106 fsType = "zfs";
107 options = [ "noauto" ];
108 };
109 };
110
111 services.nginx = {
112 enable = true;
113 virtualHosts = {
114 localhost = {
115 locations = {
116 "/zfskey" = {
117 return = ''200 "httpkeyabc"'';
118 };
119 };
120 };
121 };
122 };
123 };
124
125 testScript = ''
126 machine.wait_for_unit("multi-user.target")
127 machine.succeed(
128 "zpool status",
129 "parted --script /dev/vdb mklabel msdos",
130 "parted --script /dev/vdb -- mkpart primary 1024M -1s",
131 "parted --script /dev/vdc mklabel msdos",
132 "parted --script /dev/vdc -- mkpart primary 1024M -1s",
133 )
134
135 with subtest("sharesmb works"):
136 machine.succeed(
137 "zpool create rpool /dev/vdb1",
138 "zfs create -o mountpoint=legacy rpool/root",
139 # shared datasets cannot have legacy mountpoint
140 "zfs create rpool/shared_smb",
141 "bootctl set-default nixos-generation-1-specialisation-samba.conf",
142 "sync",
143 )
144 machine.crash()
145 machine.wait_for_unit("multi-user.target")
146 machine.succeed("zfs set sharesmb=on rpool/shared_smb")
147 machine.succeed(
148 "smbclient -gNL localhost | grep rpool_shared_smb",
149 "umount /tmp/mnt",
150 "zpool destroy rpool",
151 )
152
153 with subtest("encryption works"):
154 machine.succeed(
155 'echo password | zpool create -O mountpoint=legacy '
156 + "-O encryption=aes-256-gcm -O keyformat=passphrase automatic /dev/vdb1",
157 "zpool create -O mountpoint=legacy manual /dev/vdc1",
158 "echo otherpass | zfs create "
159 + "-o encryption=aes-256-gcm -o keyformat=passphrase manual/encrypted",
160 "zfs create -o encryption=aes-256-gcm -o keyformat=passphrase "
161 + "-o keylocation=http://localhost/zfskey manual/httpkey",
162 "bootctl set-default nixos-generation-1-specialisation-encryption.conf",
163 "sync",
164 "zpool export automatic",
165 "zpool export manual",
166 )
167 machine.crash()
168 machine.start()
169 machine.wait_for_console_text("Starting password query on")
170 machine.send_console("password\n")
171 machine.wait_for_unit("multi-user.target")
172 machine.succeed(
173 "zfs get -Ho value keystatus manual/encrypted | grep -Fx unavailable",
174 "echo otherpass | zfs load-key manual/encrypted",
175 "systemctl start manual-encrypted.mount",
176 "zfs load-key manual/httpkey",
177 "systemctl start manual-httpkey.mount",
178 "umount /automatic /manual/encrypted /manual/httpkey /manual",
179 "zpool destroy automatic",
180 "zpool destroy manual",
181 )
182
183 with subtest("boot.zfs.forceImportAll works"):
184 machine.succeed(
185 "rm /etc/hostid",
186 "zgenhostid deadcafe",
187 "zpool create forcepool /dev/vdb1 -O mountpoint=legacy",
188 "bootctl set-default nixos-generation-1-specialisation-forcepool.conf",
189 "rm /etc/hostid",
190 "sync",
191 )
192 machine.crash()
193 machine.wait_for_unit("multi-user.target")
194 machine.fail("zpool import forcepool")
195 machine.succeed(
196 "systemctl start forcepool.mount",
197 "mount | grep forcepool",
198 )
199 ''
200 + extraTest;
201
202 };
203
204in
205{
206
207 series_2_2 = makeZfsTest {
208 zfsPackage = pkgs.zfs_2_2;
209 kernelPackages = pkgs.linuxPackages;
210 };
211
212 series_2_3 = makeZfsTest {
213 zfsPackage = pkgs.zfs_2_3;
214 kernelPackages = pkgs.linuxPackages;
215 };
216
217 unstable = makeZfsTest rec {
218 zfsPackage = pkgs.zfs_unstable;
219 kernelPackages = pkgs.linuxPackages;
220 };
221
222 unstableWithSystemdStage1 = makeZfsTest rec {
223 zfsPackage = pkgs.zfs_unstable;
224 kernelPackages = pkgs.linuxPackages;
225 enableSystemdStage1 = true;
226 };
227
228 installerBoot = (import ./installer.nix { inherit system; }).separateBootZfs;
229 installer = (import ./installer.nix { inherit system; }).zfsroot;
230
231 expand-partitions = makeTest {
232 name = "multi-disk-zfs";
233 nodes = {
234 machine =
235 { pkgs, ... }:
236 {
237 environment.systemPackages = [ pkgs.parted ];
238 boot.supportedFilesystems = [ "zfs" ];
239 networking.hostId = "00000000";
240
241 virtualisation = {
242 emptyDiskImages = [
243 20480
244 20480
245 20480
246 20480
247 20480
248 20480
249 ];
250 };
251
252 specialisation.resize.configuration = {
253 services.zfs.expandOnBoot = [ "tank" ];
254 };
255 };
256 };
257
258 testScript =
259 { nodes, ... }:
260 ''
261 start_all()
262 machine.wait_for_unit("default.target")
263 print(machine.succeed('mount'))
264
265 print(machine.succeed('parted --script /dev/vdb -- mklabel gpt'))
266 print(machine.succeed('parted --script /dev/vdb -- mkpart primary 1M 70M'))
267
268 print(machine.succeed('parted --script /dev/vdc -- mklabel gpt'))
269 print(machine.succeed('parted --script /dev/vdc -- mkpart primary 1M 70M'))
270
271 print(machine.succeed('zpool create tank mirror /dev/vdb1 /dev/vdc1 mirror /dev/vdd /dev/vde mirror /dev/vdf /dev/vdg'))
272 print(machine.succeed('zpool list -v'))
273 print(machine.succeed('mount'))
274 start_size = int(machine.succeed('df -k --output=size /tank | tail -n1').strip())
275
276 print(machine.succeed("/run/current-system/specialisation/resize/bin/switch-to-configuration test >&2"))
277 machine.wait_for_unit("zpool-expand-pools.service")
278 machine.wait_for_unit("zpool-expand@tank.service")
279
280 print(machine.succeed('zpool list -v'))
281 new_size = int(machine.succeed('df -k --output=size /tank | tail -n1').strip())
282
283 if (new_size - start_size) > 20000000:
284 print("Disk grew appropriately.")
285 else:
286 print(f"Disk went from {start_size} to {new_size}, which doesn't seem right.")
287 exit(1)
288 '';
289 };
290}