python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / tests / installer.nix
blobd9f64a781c57e924c26dda6af29b1831675496cf
1 { system ? builtins.currentSystem,
2   config ? {},
3   pkgs ? import ../.. { inherit system config; },
4   systemdStage1 ? false
5 }:
7 with import ../lib/testing-python.nix { inherit system pkgs; };
8 with pkgs.lib;
10 let
12   # The configuration to install.
13   makeConfig = { bootLoader, grubVersion, grubDevice, grubIdentifier, grubUseEfi
14                , extraConfig, forceGrubReinstallCount ? 0
15                }:
16     pkgs.writeText "configuration.nix" ''
17       { config, lib, pkgs, modulesPath, ... }:
19       { imports =
20           [ ./hardware-configuration.nix
21             <nixpkgs/nixos/modules/testing/test-instrumentation.nix>
22           ];
24         # To ensure that we can rebuild the grub configuration on the nixos-rebuild
25         system.extraDependencies = with pkgs; [ stdenvNoCC ];
27         ${optionalString systemdStage1 "boot.initrd.systemd.enable = true;"}
29         ${optionalString (bootLoader == "grub") ''
30           boot.loader.grub.version = ${toString grubVersion};
31           ${optionalString (grubVersion == 1) ''
32             boot.loader.grub.splashImage = null;
33           ''}
35           boot.loader.grub.extraConfig = "serial; terminal_output serial";
36           ${if grubUseEfi then ''
37             boot.loader.grub.device = "nodev";
38             boot.loader.grub.efiSupport = true;
39             boot.loader.grub.efiInstallAsRemovable = true; # XXX: needed for OVMF?
40           '' else ''
41             boot.loader.grub.device = "${grubDevice}";
42             boot.loader.grub.fsIdentifier = "${grubIdentifier}";
43           ''}
45           boot.loader.grub.configurationLimit = 100 + ${toString forceGrubReinstallCount};
46         ''}
48         ${optionalString (bootLoader == "systemd-boot") ''
49           boot.loader.systemd-boot.enable = true;
50         ''}
52         users.users.alice = {
53           isNormalUser = true;
54           home = "/home/alice";
55           description = "Alice Foobar";
56         };
58         hardware.enableAllFirmware = lib.mkForce false;
60         ${replaceChars ["\n"] ["\n  "] extraConfig}
61       }
62     '';
65   # The test script boots a NixOS VM, installs NixOS on an empty hard
66   # disk, and then reboot from the hard disk.  It's parameterized with
67   # a test script fragment `createPartitions', which must create
68   # partitions and filesystems.
69   testScriptFun = { bootLoader, createPartitions, grubVersion, grubDevice, grubUseEfi
70                   , grubIdentifier, preBootCommands, postBootCommands, extraConfig
71                   , testSpecialisationConfig
72                   }:
73     let iface = if grubVersion == 1 then "ide" else "virtio";
74         isEfi = bootLoader == "systemd-boot" || (bootLoader == "grub" && grubUseEfi);
75         bios  = if pkgs.stdenv.isAarch64 then "QEMU_EFI.fd" else "OVMF.fd";
76     in if !isEfi && !pkgs.stdenv.hostPlatform.isx86 then
77       throw "Non-EFI boot methods are only supported on i686 / x86_64"
78     else ''
79       def assemble_qemu_flags():
80           flags = "-cpu max"
81           ${if (system == "x86_64-linux" || system == "i686-linux")
82             then ''flags += " -m 1024"''
83             else ''flags += " -m 768 -enable-kvm -machine virt,gic-version=host"''
84           }
85           return flags
88       qemu_flags = {"qemuFlags": assemble_qemu_flags()}
90       hd_flags = {
91           "hdaInterface": "${iface}",
92           "hda": "vm-state-machine/machine.qcow2",
93       }
94       ${optionalString isEfi ''
95         hd_flags.update(
96             bios="${pkgs.OVMF.fd}/FV/${bios}"
97         )''
98       }
99       default_flags = {**hd_flags, **qemu_flags}
102       def create_machine_named(name):
103           return create_machine({**default_flags, "name": name})
106       machine.start()
108       with subtest("Assert readiness of login prompt"):
109           machine.succeed("echo hello")
111       with subtest("Wait for hard disks to appear in /dev"):
112           machine.succeed("udevadm settle")
114       ${createPartitions}
116       with subtest("Create the NixOS configuration"):
117           machine.succeed("nixos-generate-config --root /mnt")
118           machine.succeed("cat /mnt/etc/nixos/hardware-configuration.nix >&2")
119           machine.copy_from_host(
120               "${ makeConfig {
121                     inherit bootLoader grubVersion grubDevice grubIdentifier
122                             grubUseEfi extraConfig;
123                   }
124               }",
125               "/mnt/etc/nixos/configuration.nix",
126           )
128       with subtest("Perform the installation"):
129           machine.succeed("nixos-install < /dev/null >&2")
131       with subtest("Do it again to make sure it's idempotent"):
132           machine.succeed("nixos-install < /dev/null >&2")
134       with subtest("Shutdown system after installation"):
135           machine.succeed("umount /mnt/boot || true")
136           machine.succeed("umount /mnt")
137           machine.succeed("sync")
138           machine.shutdown()
140       # Now see if we can boot the installation.
141       machine = create_machine_named("boot-after-install")
143       # For example to enter LUKS passphrase.
144       ${preBootCommands}
146       with subtest("Assert that /boot get mounted"):
147           machine.wait_for_unit("local-fs.target")
148           ${if bootLoader == "grub"
149               then ''machine.succeed("test -e /boot/grub")''
150               else ''machine.succeed("test -e /boot/loader/loader.conf")''
151           }
153       with subtest("Check whether /root has correct permissions"):
154           assert "700" in machine.succeed("stat -c '%a' /root")
156       with subtest("Assert swap device got activated"):
157           # uncomment once https://bugs.freedesktop.org/show_bug.cgi?id=86930 is resolved
158           machine.wait_for_unit("swap.target")
159           machine.succeed("cat /proc/swaps | grep -q /dev")
161       with subtest("Check that the store is in good shape"):
162           machine.succeed("nix-store --verify --check-contents >&2")
164       with subtest("Check whether the channel works"):
165           machine.succeed("nix-env -iA nixos.procps >&2")
166           assert ".nix-profile" in machine.succeed("type -tP ps | tee /dev/stderr")
168       with subtest(
169           "Check that the daemon works, and that non-root users can run builds "
170           "(this will build a new profile generation through the daemon)"
171       ):
172           machine.succeed("su alice -l -c 'nix-env -iA nixos.procps' >&2")
174       with subtest("Configure system with writable Nix store on next boot"):
175           # we're not using copy_from_host here because the installer image
176           # doesn't know about the host-guest sharing mechanism.
177           machine.copy_from_host_via_shell(
178               "${ makeConfig {
179                     inherit bootLoader grubVersion grubDevice grubIdentifier
180                             grubUseEfi extraConfig;
181                     forceGrubReinstallCount = 1;
182                   }
183               }",
184               "/etc/nixos/configuration.nix",
185           )
187       with subtest("Check whether nixos-rebuild works"):
188           machine.succeed("nixos-rebuild switch >&2")
190       # FIXME: Nix 2.4 broke nixos-option, someone has to fix it.
191       # with subtest("Test nixos-option"):
192       #     kernel_modules = machine.succeed("nixos-option boot.initrd.kernelModules")
193       #     assert "virtio_console" in kernel_modules
194       #     assert "List of modules" in kernel_modules
195       #     assert "qemu-guest.nix" in kernel_modules
197       machine.shutdown()
199       # Check whether a writable store build works
200       machine = create_machine_named("rebuild-switch")
201       ${preBootCommands}
202       machine.wait_for_unit("multi-user.target")
204       # we're not using copy_from_host here because the installer image
205       # doesn't know about the host-guest sharing mechanism.
206       machine.copy_from_host_via_shell(
207           "${ makeConfig {
208                 inherit bootLoader grubVersion grubDevice grubIdentifier
209                 grubUseEfi extraConfig;
210                 forceGrubReinstallCount = 2;
211               }
212           }",
213           "/etc/nixos/configuration.nix",
214       )
215       machine.succeed("nixos-rebuild boot >&2")
216       machine.shutdown()
218       # And just to be sure, check that the machine still boots after
219       # "nixos-rebuild switch".
220       machine = create_machine_named("boot-after-rebuild-switch")
221       ${preBootCommands}
222       machine.wait_for_unit("network.target")
223       ${postBootCommands}
224       machine.shutdown()
226       # Tests for validating clone configuration entries in grub menu
227     ''
228     + optionalString testSpecialisationConfig ''
229       # Reboot Machine
230       machine = create_machine_named("clone-default-config")
231       ${preBootCommands}
232       machine.wait_for_unit("multi-user.target")
234       with subtest("Booted configuration name should be 'Home'"):
235           # This is not the name that shows in the grub menu.
236           # The default configuration is always shown as "Default"
237           machine.succeed("cat /run/booted-system/configuration-name >&2")
238           assert "Home" in machine.succeed("cat /run/booted-system/configuration-name")
240       with subtest("We should **not** find a file named /etc/gitconfig"):
241           machine.fail("test -e /etc/gitconfig")
243       with subtest("Set grub to boot the second configuration"):
244           machine.succeed("grub-reboot 1")
246       ${postBootCommands}
247       machine.shutdown()
249       # Reboot Machine
250       machine = create_machine_named("clone-alternate-config")
251       ${preBootCommands}
253       machine.wait_for_unit("multi-user.target")
254       with subtest("Booted configuration name should be Work"):
255           machine.succeed("cat /run/booted-system/configuration-name >&2")
256           assert "Work" in machine.succeed("cat /run/booted-system/configuration-name")
258       with subtest("We should find a file named /etc/gitconfig"):
259           machine.succeed("test -e /etc/gitconfig")
261       ${postBootCommands}
262       machine.shutdown()
263     '';
266   makeInstallerTest = name:
267     { createPartitions, preBootCommands ? "", postBootCommands ? "", extraConfig ? ""
268     , extraInstallerConfig ? {}
269     , bootLoader ? "grub" # either "grub" or "systemd-boot"
270     , grubVersion ? 2, grubDevice ? "/dev/vda", grubIdentifier ? "uuid", grubUseEfi ? false
271     , enableOCR ? false, meta ? {}
272     , testSpecialisationConfig ? false
273     }:
274     makeTest {
275       inherit enableOCR;
276       name = "installer-" + name;
277       meta = with pkgs.lib.maintainers; {
278         # put global maintainers here, individuals go into makeInstallerTest fkt call
279         maintainers = (meta.maintainers or []);
280       };
281       nodes = {
283         # The configuration of the machine used to run "nixos-install".
284         machine = { pkgs, ... }: {
285           imports = [
286             ../modules/profiles/installation-device.nix
287             ../modules/profiles/base.nix
288             extraInstallerConfig
289           ];
291           # builds stuff in the VM, needs more juice
292           virtualisation.diskSize = 8 * 1024;
293           virtualisation.cores = 8;
294           virtualisation.memorySize = 1536;
296           boot.initrd.systemd.enable = systemdStage1;
298           # Use a small /dev/vdb as the root disk for the
299           # installer. This ensures the target disk (/dev/vda) is
300           # the same during and after installation.
301           virtualisation.emptyDiskImages = [ 512 ];
302           virtualisation.bootDevice =
303             if grubVersion == 1 then "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive2" else "/dev/vdb";
304           virtualisation.qemu.diskInterface =
305             if grubVersion == 1 then "scsi" else "virtio";
307           # We don't want to have any networking in the guest whatsoever.
308           # Also, if any vlans are enabled, the guest will reboot
309           # (with a different configuration for legacy reasons),
310           # and spend 5 minutes waiting for the vlan interface to show up
311           # (which will never happen).
312           virtualisation.vlans = [];
314           boot.loader.systemd-boot.enable = mkIf (bootLoader == "systemd-boot") true;
316           hardware.enableAllFirmware = mkForce false;
318           # The test cannot access the network, so any packages we
319           # need must be included in the VM.
320           system.extraDependencies = with pkgs; [
321             brotli
322             brotli.dev
323             brotli.lib
324             desktop-file-utils
325             docbook5
326             docbook_xsl_ns
327             (docbook-xsl-ns.override {
328               withManOptDedupPatch = true;
329             })
330             kmod.dev
331             libarchive.dev
332             libxml2.bin
333             libxslt.bin
334             nixos-artwork.wallpapers.simple-dark-gray-bottom
335             ntp
336             perlPackages.ListCompare
337             perlPackages.XMLLibXML
338             python3Minimal
339             # make-options-doc/default.nix
340             (let
341                 self = (pkgs.python3Minimal.override {
342                   inherit self;
343                   includeSiteCustomize = true;
344                 });
345               in self.withPackages (p: [ p.mistune ]))
346             shared-mime-info
347             sudo
348             texinfo
349             unionfs-fuse
350             xorg.lndir
352             # add curl so that rather than seeing the test attempt to download
353             # curl's tarball, we see what it's trying to download
354             curl
355           ]
356           ++ optional (bootLoader == "grub" && grubVersion == 1) pkgs.grub
357           ++ optionals (bootLoader == "grub" && grubVersion == 2) (let
358             zfsSupport = lib.any (x: x == "zfs")
359               (extraInstallerConfig.boot.supportedFilesystems or []);
360           in [
361             (pkgs.grub2.override { inherit zfsSupport; })
362             (pkgs.grub2_efi.override { inherit zfsSupport; })
363           ]);
365           nix.settings = {
366             substituters = mkForce [];
367             hashed-mirrors = null;
368             connect-timeout = 1;
369           };
370         };
372       };
374       testScript = testScriptFun {
375         inherit bootLoader createPartitions preBootCommands postBootCommands
376                 grubVersion grubDevice grubIdentifier grubUseEfi extraConfig
377                 testSpecialisationConfig;
378       };
379     };
381     makeLuksRootTest = name: luksFormatOpts: makeInstallerTest name {
382       createPartitions = ''
383         machine.succeed(
384             "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
385             + " mkpart primary ext2 1M 100MB"  # /boot
386             + " mkpart primary linux-swap 100M 1024M"
387             + " mkpart primary 1024M -1s",  # LUKS
388             "udevadm settle",
389             "mkswap /dev/vda2 -L swap",
390             "swapon -L swap",
391             "modprobe dm_mod dm_crypt",
392             "echo -n supersecret | cryptsetup luksFormat ${luksFormatOpts} -q /dev/vda3 -",
393             "echo -n supersecret | cryptsetup luksOpen --key-file - /dev/vda3 cryptroot",
394             "mkfs.ext3 -L nixos /dev/mapper/cryptroot",
395             "mount LABEL=nixos /mnt",
396             "mkfs.ext3 -L boot /dev/vda1",
397             "mkdir -p /mnt/boot",
398             "mount LABEL=boot /mnt/boot",
399         )
400       '';
401       extraConfig = ''
402         boot.kernelParams = lib.mkAfter [ "console=tty0" ];
403       '';
404       enableOCR = true;
405       preBootCommands = ''
406         machine.start()
407         machine.wait_for_text("Passphrase for")
408         machine.send_chars("supersecret\n")
409       '';
410     };
412   # The (almost) simplest partitioning scheme: a swap partition and
413   # one big filesystem partition.
414   simple-test-config = {
415     createPartitions = ''
416       machine.succeed(
417           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
418           + " mkpart primary linux-swap 1M 1024M"
419           + " mkpart primary ext2 1024M -1s",
420           "udevadm settle",
421           "mkswap /dev/vda1 -L swap",
422           "swapon -L swap",
423           "mkfs.ext3 -L nixos /dev/vda2",
424           "mount LABEL=nixos /mnt",
425       )
426     '';
427   };
429   simple-uefi-grub-config = {
430     createPartitions = ''
431       machine.succeed(
432           "flock /dev/vda parted --script /dev/vda -- mklabel gpt"
433           + " mkpart ESP fat32 1M 100MiB"  # /boot
434           + " set 1 boot on"
435           + " mkpart primary linux-swap 100MiB 1024MiB"
436           + " mkpart primary ext2 1024MiB -1MiB",  # /
437           "udevadm settle",
438           "mkswap /dev/vda2 -L swap",
439           "swapon -L swap",
440           "mkfs.ext3 -L nixos /dev/vda3",
441           "mount LABEL=nixos /mnt",
442           "mkfs.vfat -n BOOT /dev/vda1",
443           "mkdir -p /mnt/boot",
444           "mount LABEL=BOOT /mnt/boot",
445       )
446     '';
447     bootLoader = "grub";
448     grubUseEfi = true;
449   };
451   specialisation-test-extraconfig = {
452     extraConfig = ''
453       environment.systemPackages = [ pkgs.grub2 ];
454       boot.loader.grub.configurationName = "Home";
455       specialisation.work.configuration = {
456         boot.loader.grub.configurationName = lib.mkForce "Work";
458         environment.etc = {
459           "gitconfig".text = "
460             [core]
461               gitproxy = none for work.com
462               ";
463         };
464       };
465     '';
466     testSpecialisationConfig = true;
467   };
470 in {
472   # !!! `parted mkpart' seems to silently create overlapping partitions.
475   # The (almost) simplest partitioning scheme: a swap partition and
476   # one big filesystem partition.
477   simple = makeInstallerTest "simple" simple-test-config;
479   # Test cloned configurations with the simple grub configuration
480   simpleSpecialised = makeInstallerTest "simpleSpecialised" (simple-test-config // specialisation-test-extraconfig);
482   # Simple GPT/UEFI configuration using systemd-boot with 3 partitions: ESP, swap & root filesystem
483   simpleUefiSystemdBoot = makeInstallerTest "simpleUefiSystemdBoot" {
484     createPartitions = ''
485       machine.succeed(
486           "flock /dev/vda parted --script /dev/vda -- mklabel gpt"
487           + " mkpart ESP fat32 1M 100MiB"  # /boot
488           + " set 1 boot on"
489           + " mkpart primary linux-swap 100MiB 1024MiB"
490           + " mkpart primary ext2 1024MiB -1MiB",  # /
491           "udevadm settle",
492           "mkswap /dev/vda2 -L swap",
493           "swapon -L swap",
494           "mkfs.ext3 -L nixos /dev/vda3",
495           "mount LABEL=nixos /mnt",
496           "mkfs.vfat -n BOOT /dev/vda1",
497           "mkdir -p /mnt/boot",
498           "mount LABEL=BOOT /mnt/boot",
499       )
500     '';
501     bootLoader = "systemd-boot";
502   };
504   simpleUefiGrub = makeInstallerTest "simpleUefiGrub" simple-uefi-grub-config;
506   # Test cloned configurations with the uefi grub configuration
507   simpleUefiGrubSpecialisation = makeInstallerTest "simpleUefiGrubSpecialisation" (simple-uefi-grub-config // specialisation-test-extraconfig);
509   # Same as the previous, but now with a separate /boot partition.
510   separateBoot = makeInstallerTest "separateBoot" {
511     createPartitions = ''
512       machine.succeed(
513           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
514           + " mkpart primary ext2 1M 100MB"  # /boot
515           + " mkpart primary linux-swap 100MB 1024M"
516           + " mkpart primary ext2 1024M -1s",  # /
517           "udevadm settle",
518           "mkswap /dev/vda2 -L swap",
519           "swapon -L swap",
520           "mkfs.ext3 -L nixos /dev/vda3",
521           "mount LABEL=nixos /mnt",
522           "mkfs.ext3 -L boot /dev/vda1",
523           "mkdir -p /mnt/boot",
524           "mount LABEL=boot /mnt/boot",
525       )
526     '';
527   };
529   # Same as the previous, but with fat32 /boot.
530   separateBootFat = makeInstallerTest "separateBootFat" {
531     createPartitions = ''
532       machine.succeed(
533           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
534           + " mkpart primary ext2 1M 100MB"  # /boot
535           + " mkpart primary linux-swap 100MB 1024M"
536           + " mkpart primary ext2 1024M -1s",  # /
537           "udevadm settle",
538           "mkswap /dev/vda2 -L swap",
539           "swapon -L swap",
540           "mkfs.ext3 -L nixos /dev/vda3",
541           "mount LABEL=nixos /mnt",
542           "mkfs.vfat -n BOOT /dev/vda1",
543           "mkdir -p /mnt/boot",
544           "mount LABEL=BOOT /mnt/boot",
545       )
546     '';
547   };
549   # zfs on / with swap
550   zfsroot = makeInstallerTest "zfs-root" {
551     extraInstallerConfig = {
552       boot.supportedFilesystems = [ "zfs" ];
553     };
555     extraConfig = ''
556       boot.supportedFilesystems = [ "zfs" ];
558       # Using by-uuid overrides the default of by-id, and is unique
559       # to the qemu disks, as they don't produce by-id paths for
560       # some reason.
561       boot.zfs.devNodes = "/dev/disk/by-uuid/";
562       networking.hostId = "00000000";
563     '';
565     createPartitions = ''
566       machine.succeed(
567           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
568           + " mkpart primary linux-swap 1M 1024M"
569           + " mkpart primary 1024M -1s",
570           "udevadm settle",
571           "mkswap /dev/vda1 -L swap",
572           "swapon -L swap",
573           "zpool create rpool /dev/vda2",
574           "zfs create -o mountpoint=legacy rpool/root",
575           "mount -t zfs rpool/root /mnt",
576           "udevadm settle",
577       )
578     '';
579   };
581   # Create two physical LVM partitions combined into one volume group
582   # that contains the logical swap and root partitions.
583   lvm = makeInstallerTest "lvm" {
584     createPartitions = ''
585       machine.succeed(
586           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
587           + " mkpart primary 1M 2048M"  # PV1
588           + " set 1 lvm on"
589           + " mkpart primary 2048M -1s"  # PV2
590           + " set 2 lvm on",
591           "udevadm settle",
592           "pvcreate /dev/vda1 /dev/vda2",
593           "vgcreate MyVolGroup /dev/vda1 /dev/vda2",
594           "lvcreate --size 1G --name swap MyVolGroup",
595           "lvcreate --size 6G --name nixos MyVolGroup",
596           "mkswap -f /dev/MyVolGroup/swap -L swap",
597           "swapon -L swap",
598           "mkfs.xfs -L nixos /dev/MyVolGroup/nixos",
599           "mount LABEL=nixos /mnt",
600       )
601     '';
602   };
604   # Boot off an encrypted root partition with the default LUKS header format
605   luksroot = makeLuksRootTest "luksroot-format1" "";
607   # Boot off an encrypted root partition with LUKS1 format
608   luksroot-format1 = makeLuksRootTest "luksroot-format1" "--type=LUKS1";
610   # Boot off an encrypted root partition with LUKS2 format
611   luksroot-format2 = makeLuksRootTest "luksroot-format2" "--type=LUKS2";
613   # Test whether opening encrypted filesystem with keyfile
614   # Checks for regression of missing cryptsetup, when no luks device without
615   # keyfile is configured
616   encryptedFSWithKeyfile = makeInstallerTest "encryptedFSWithKeyfile" {
617     createPartitions = ''
618       machine.succeed(
619           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
620           + " mkpart primary ext2 1M 100MB"  # /boot
621           + " mkpart primary linux-swap 100M 1024M"
622           + " mkpart primary 1024M 1280M"  # LUKS with keyfile
623           + " mkpart primary 1280M -1s",
624           "udevadm settle",
625           "mkswap /dev/vda2 -L swap",
626           "swapon -L swap",
627           "mkfs.ext3 -L nixos /dev/vda4",
628           "mount LABEL=nixos /mnt",
629           "mkfs.ext3 -L boot /dev/vda1",
630           "mkdir -p /mnt/boot",
631           "mount LABEL=boot /mnt/boot",
632           "modprobe dm_mod dm_crypt",
633           "echo -n supersecret > /mnt/keyfile",
634           "cryptsetup luksFormat -q /dev/vda3 --key-file /mnt/keyfile",
635           "cryptsetup luksOpen --key-file /mnt/keyfile /dev/vda3 crypt",
636           "mkfs.ext3 -L test /dev/mapper/crypt",
637           "cryptsetup luksClose crypt",
638           "mkdir -p /mnt/test",
639       )
640     '';
641     extraConfig = ''
642       fileSystems."/test" = {
643         device = "/dev/disk/by-label/test";
644         fsType = "ext3";
645         encrypted.enable = true;
646         encrypted.blkDev = "/dev/vda3";
647         encrypted.label = "crypt";
648         encrypted.keyFile = "/mnt-root/keyfile";
649       };
650     '';
651   };
653   swraid = makeInstallerTest "swraid" {
654     createPartitions = ''
655       machine.succeed(
656           "flock /dev/vda parted --script /dev/vda --"
657           + " mklabel msdos"
658           + " mkpart primary ext2 1M 100MB"  # /boot
659           + " mkpart extended 100M -1s"
660           + " mkpart logical 102M 3102M"  # md0 (root), first device
661           + " mkpart logical 3103M 6103M"  # md0 (root), second device
662           + " mkpart logical 6104M 6360M"  # md1 (swap), first device
663           + " mkpart logical 6361M 6617M",  # md1 (swap), second device
664           "udevadm settle",
665           "ls -l /dev/vda* >&2",
666           "cat /proc/partitions >&2",
667           "udevadm control --stop-exec-queue",
668           "mdadm --create --force /dev/md0 --metadata 1.2 --level=raid1 "
669           + "--raid-devices=2 /dev/vda5 /dev/vda6",
670           "mdadm --create --force /dev/md1 --metadata 1.2 --level=raid1 "
671           + "--raid-devices=2 /dev/vda7 /dev/vda8",
672           "udevadm control --start-exec-queue",
673           "udevadm settle",
674           "mkswap -f /dev/md1 -L swap",
675           "swapon -L swap",
676           "mkfs.ext3 -L nixos /dev/md0",
677           "mount LABEL=nixos /mnt",
678           "mkfs.ext3 -L boot /dev/vda1",
679           "mkdir /mnt/boot",
680           "mount LABEL=boot /mnt/boot",
681           "udevadm settle",
682       )
683     '';
684     preBootCommands = ''
685       machine.start()
686       machine.fail("dmesg | grep 'immediate safe mode'")
687     '';
688   };
690   bcache = makeInstallerTest "bcache" {
691     createPartitions = ''
692       machine.succeed(
693           "flock /dev/vda parted --script /dev/vda --"
694           + " mklabel msdos"
695           + " mkpart primary ext2 1M 100MB"  # /boot
696           + " mkpart primary 100MB 512MB  "  # swap
697           + " mkpart primary 512MB 1024MB"  # Cache (typically SSD)
698           + " mkpart primary 1024MB -1s ",  # Backing device (typically HDD)
699           "modprobe bcache",
700           "udevadm settle",
701           "make-bcache -B /dev/vda4 -C /dev/vda3",
702           "udevadm settle",
703           "mkfs.ext3 -L nixos /dev/bcache0",
704           "mount LABEL=nixos /mnt",
705           "mkfs.ext3 -L boot /dev/vda1",
706           "mkdir /mnt/boot",
707           "mount LABEL=boot /mnt/boot",
708           "mkswap -f /dev/vda2 -L swap",
709           "swapon -L swap",
710       )
711     '';
712   };
714   bcachefsSimple = makeInstallerTest "bcachefs-simple" {
715     extraInstallerConfig = {
716       boot.supportedFilesystems = [ "bcachefs" ];
717     };
719     createPartitions = ''
720       machine.succeed(
721         "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
722         + " mkpart primary ext2 1M 100MB"          # /boot
723         + " mkpart primary linux-swap 100M 1024M"  # swap
724         + " mkpart primary 1024M -1s",             # /
725         "udevadm settle",
726         "mkswap /dev/vda2 -L swap",
727         "swapon -L swap",
728         "mkfs.bcachefs -L root /dev/vda3",
729         "mount -t bcachefs /dev/vda3 /mnt",
730         "mkfs.ext3 -L boot /dev/vda1",
731         "mkdir -p /mnt/boot",
732         "mount /dev/vda1 /mnt/boot",
733       )
734     '';
735   };
737   bcachefsEncrypted = makeInstallerTest "bcachefs-encrypted" {
738     extraInstallerConfig = {
739       boot.supportedFilesystems = [ "bcachefs" ];
740       environment.systemPackages = with pkgs; [ keyutils ];
741     };
743     # We don't want to use the normal way of unlocking bcachefs defined in tasks/filesystems/bcachefs.nix.
744     # So, override initrd.postDeviceCommands completely and simply unlock with the predefined password.
745     extraConfig = ''
746       boot.initrd.postDeviceCommands = lib.mkForce "echo password | bcachefs unlock /dev/vda3";
747     '';
749     createPartitions = ''
750       machine.succeed(
751         "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
752         + " mkpart primary ext2 1M 100MB"          # /boot
753         + " mkpart primary linux-swap 100M 1024M"  # swap
754         + " mkpart primary 1024M -1s",             # /
755         "udevadm settle",
756         "mkswap /dev/vda2 -L swap",
757         "swapon -L swap",
758         "keyctl link @u @s",
759         "echo password | mkfs.bcachefs -L root --encrypted /dev/vda3",
760         "echo password | bcachefs unlock /dev/vda3",
761         "mount -t bcachefs /dev/vda3 /mnt",
762         "mkfs.ext3 -L boot /dev/vda1",
763         "mkdir -p /mnt/boot",
764         "mount /dev/vda1 /mnt/boot",
765       )
766     '';
767   };
769   bcachefsMulti = makeInstallerTest "bcachefs-multi" {
770     extraInstallerConfig = {
771       boot.supportedFilesystems = [ "bcachefs" ];
772     };
774     createPartitions = ''
775       machine.succeed(
776         "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
777         + " mkpart primary ext2 1M 100MB"          # /boot
778         + " mkpart primary linux-swap 100M 1024M"  # swap
779         + " mkpart primary 1024M 4096M"            # /
780         + " mkpart primary 4096M -1s",             # /
781         "udevadm settle",
782         "mkswap /dev/vda2 -L swap",
783         "swapon -L swap",
784         "mkfs.bcachefs -L root --metadata_replicas 2 --foreground_target ssd --promote_target ssd --background_target hdd --label ssd /dev/vda3 --label hdd /dev/vda4",
785         "mount -t bcachefs /dev/vda3:/dev/vda4 /mnt",
786         "mkfs.ext3 -L boot /dev/vda1",
787         "mkdir -p /mnt/boot",
788         "mount /dev/vda1 /mnt/boot",
789       )
790     '';
791   };
793   # Test a basic install using GRUB 1.
794   grub1 = makeInstallerTest "grub1" rec {
795     createPartitions = ''
796       machine.succeed(
797           "flock ${grubDevice} parted --script ${grubDevice} -- mklabel msdos"
798           + " mkpart primary linux-swap 1M 1024M"
799           + " mkpart primary ext2 1024M -1s",
800           "udevadm settle",
801           "mkswap ${grubDevice}-part1 -L swap",
802           "swapon -L swap",
803           "mkfs.ext3 -L nixos ${grubDevice}-part2",
804           "mount LABEL=nixos /mnt",
805           "mkdir -p /mnt/tmp",
806       )
807     '';
808     grubVersion = 1;
809     # /dev/sda is not stable, even when the SCSI disk number is.
810     grubDevice = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive1";
811   };
813   # Test using labels to identify volumes in grub
814   simpleLabels = makeInstallerTest "simpleLabels" {
815     createPartitions = ''
816       machine.succeed(
817           "sgdisk -Z /dev/vda",
818           "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda",
819           "mkswap /dev/vda2 -L swap",
820           "swapon -L swap",
821           "mkfs.ext4 -L root /dev/vda3",
822           "mount LABEL=root /mnt",
823       )
824     '';
825     grubIdentifier = "label";
826   };
828   # Test using the provided disk name within grub
829   # TODO: Fix udev so the symlinks are unneeded in /dev/disks
830   simpleProvided = makeInstallerTest "simpleProvided" {
831     createPartitions = ''
832       uuid = "$(blkid -s UUID -o value /dev/vda2)"
833       machine.succeed(
834           "sgdisk -Z /dev/vda",
835           "sgdisk -n 1:0:+1M -n 2:0:+100M -n 3:0:+1G -N 4 -t 1:ef02 -t 2:8300 "
836           + "-t 3:8200 -t 4:8300 -c 2:boot -c 4:root /dev/vda",
837           "mkswap /dev/vda3 -L swap",
838           "swapon -L swap",
839           "mkfs.ext4 -L boot /dev/vda2",
840           "mkfs.ext4 -L root /dev/vda4",
841       )
842       machine.execute(f"ln -s ../../vda2 /dev/disk/by-uuid/{uuid}")
843       machine.execute("ln -s ../../vda4 /dev/disk/by-label/root")
844       machine.succeed(
845           "mount /dev/disk/by-label/root /mnt",
846           "mkdir /mnt/boot",
847           f"mount /dev/disk/by-uuid/{uuid} /mnt/boot",
848       )
849     '';
850     grubIdentifier = "provided";
851   };
853   # Simple btrfs grub testing
854   btrfsSimple = makeInstallerTest "btrfsSimple" {
855     createPartitions = ''
856       machine.succeed(
857           "sgdisk -Z /dev/vda",
858           "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda",
859           "mkswap /dev/vda2 -L swap",
860           "swapon -L swap",
861           "mkfs.btrfs -L root /dev/vda3",
862           "mount LABEL=root /mnt",
863       )
864     '';
865   };
867   # Test to see if we can detect /boot and /nix on subvolumes
868   btrfsSubvols = makeInstallerTest "btrfsSubvols" {
869     createPartitions = ''
870       machine.succeed(
871           "sgdisk -Z /dev/vda",
872           "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda",
873           "mkswap /dev/vda2 -L swap",
874           "swapon -L swap",
875           "mkfs.btrfs -L root /dev/vda3",
876           "btrfs device scan",
877           "mount LABEL=root /mnt",
878           "btrfs subvol create /mnt/boot",
879           "btrfs subvol create /mnt/nixos",
880           "btrfs subvol create /mnt/nixos/default",
881           "umount /mnt",
882           "mount -o defaults,subvol=nixos/default LABEL=root /mnt",
883           "mkdir /mnt/boot",
884           "mount -o defaults,subvol=boot LABEL=root /mnt/boot",
885       )
886     '';
887   };
889   # Test to see if we can detect default and aux subvolumes correctly
890   btrfsSubvolDefault = makeInstallerTest "btrfsSubvolDefault" {
891     createPartitions = ''
892       machine.succeed(
893           "sgdisk -Z /dev/vda",
894           "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda",
895           "mkswap /dev/vda2 -L swap",
896           "swapon -L swap",
897           "mkfs.btrfs -L root /dev/vda3",
898           "btrfs device scan",
899           "mount LABEL=root /mnt",
900           "btrfs subvol create /mnt/badpath",
901           "btrfs subvol create /mnt/badpath/boot",
902           "btrfs subvol create /mnt/nixos",
903           "btrfs subvol set-default "
904           + "$(btrfs subvol list /mnt | grep 'nixos' | awk '{print $2}') /mnt",
905           "umount /mnt",
906           "mount -o defaults LABEL=root /mnt",
907           "mkdir -p /mnt/badpath/boot",  # Help ensure the detection mechanism
908           # is actually looking up subvolumes
909           "mkdir /mnt/boot",
910           "mount -o defaults,subvol=badpath/boot LABEL=root /mnt/boot",
911       )
912     '';
913   };