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