at 17.09-beta 21 kB view raw
1{ system ? builtins.currentSystem }: 2 3with import ../lib/testing.nix { inherit system; }; 4with import ../lib/qemu-flags.nix; 5with pkgs.lib; 6 7let 8 9 # The configuration to install. 10 makeConfig = { bootLoader, grubVersion, grubDevice, grubIdentifier 11 , extraConfig, forceGrubReinstallCount ? 0 12 }: 13 pkgs.writeText "configuration.nix" '' 14 { config, lib, pkgs, modulesPath, ... }: 15 16 { imports = 17 [ ./hardware-configuration.nix 18 <nixpkgs/nixos/modules/testing/test-instrumentation.nix> 19 ]; 20 21 # To ensure that we can rebuild the grub configuration on the nixos-rebuild 22 system.extraDependencies = with pkgs; [ stdenvNoCC ]; 23 24 ${optionalString (bootLoader == "grub") '' 25 boot.loader.grub.version = ${toString grubVersion}; 26 ${optionalString (grubVersion == 1) '' 27 boot.loader.grub.splashImage = null; 28 ''} 29 boot.loader.grub.device = "${grubDevice}"; 30 boot.loader.grub.extraConfig = "serial; terminal_output.serial"; 31 boot.loader.grub.fsIdentifier = "${grubIdentifier}"; 32 33 boot.loader.grub.configurationLimit = 100 + ${toString forceGrubReinstallCount}; 34 ''} 35 36 ${optionalString (bootLoader == "systemd-boot") '' 37 boot.loader.systemd-boot.enable = true; 38 ''} 39 40 users.extraUsers.alice = { 41 isNormalUser = true; 42 home = "/home/alice"; 43 description = "Alice Foobar"; 44 }; 45 46 hardware.enableAllFirmware = lib.mkForce false; 47 48 ${replaceChars ["\n"] ["\n "] extraConfig} 49 } 50 ''; 51 52 53 channelContents = [ pkgs.rlwrap ]; 54 55 56 # The test script boots a NixOS VM, installs NixOS on an empty hard 57 # disk, and then reboot from the hard disk. It's parameterized with 58 # a test script fragment `createPartitions', which must create 59 # partitions and filesystems. 60 testScriptFun = { bootLoader, createPartitions, grubVersion, grubDevice 61 , grubIdentifier, preBootCommands, extraConfig 62 }: 63 let 64 iface = if grubVersion == 1 then "ide" else "virtio"; 65 qemuFlags = 66 (if system == "x86_64-linux" then "-m 768 " else "-m 512 ") + 67 (optionalString (system == "x86_64-linux") "-cpu kvm64 "); 68 hdFlags = ''hda => "vm-state-machine/machine.qcow2", hdaInterface => "${iface}", '' 69 + optionalString (bootLoader == "systemd-boot") ''bios => "${pkgs.OVMF.fd}/FV/OVMF.fd", ''; 70 in 71 '' 72 $machine->start; 73 74 # Make sure that we get a login prompt etc. 75 $machine->succeed("echo hello"); 76 #$machine->waitForUnit('getty@tty2'); 77 #$machine->waitForUnit("rogue"); 78 $machine->waitForUnit("nixos-manual"); 79 80 # Wait for hard disks to appear in /dev 81 $machine->succeed("udevadm settle"); 82 83 # Partition the disk. 84 ${createPartitions} 85 86 # Create the NixOS configuration. 87 $machine->succeed("nixos-generate-config --root /mnt"); 88 89 $machine->succeed("cat /mnt/etc/nixos/hardware-configuration.nix >&2"); 90 91 $machine->copyFileFromHost( 92 "${ makeConfig { inherit bootLoader grubVersion grubDevice grubIdentifier extraConfig; } }", 93 "/mnt/etc/nixos/configuration.nix"); 94 95 # Perform the installation. 96 $machine->succeed("nixos-install < /dev/null >&2"); 97 98 # Do it again to make sure it's idempotent. 99 $machine->succeed("nixos-install < /dev/null >&2"); 100 101 $machine->succeed("umount /mnt/boot || true"); 102 $machine->succeed("umount /mnt"); 103 $machine->succeed("sync"); 104 105 $machine->shutdown; 106 107 # Now see if we can boot the installation. 108 $machine = createMachine({ ${hdFlags} qemuFlags => "${qemuFlags}", name => "boot-after-install" }); 109 110 # For example to enter LUKS passphrase. 111 ${preBootCommands} 112 113 # Did /boot get mounted? 114 $machine->waitForUnit("local-fs.target"); 115 116 ${if bootLoader == "grub" then 117 ''$machine->succeed("test -e /boot/grub");'' 118 else 119 ''$machine->succeed("test -e /boot/loader/loader.conf");'' 120 } 121 122 # Check whether /root has correct permissions. 123 $machine->succeed("stat -c '%a' /root") =~ /700/ or die; 124 125 # Did the swap device get activated? 126 # uncomment once https://bugs.freedesktop.org/show_bug.cgi?id=86930 is resolved 127 $machine->waitForUnit("swap.target"); 128 $machine->succeed("cat /proc/swaps | grep -q /dev"); 129 130 # Check that the store is in good shape 131 $machine->succeed("nix-store --verify --check-contents >&2"); 132 133 # Check whether the channel works. 134 $machine->succeed("nix-env -iA nixos.procps >&2"); 135 $machine->succeed("type -tP ps | tee /dev/stderr") =~ /.nix-profile/ 136 or die "nix-env failed"; 137 138 # Check that the daemon works, and that non-root users can run builds (this will build a new profile generation through the daemon) 139 $machine->succeed("su alice -l -c 'nix-env -iA nixos.procps' >&2"); 140 141 # We need to a writable nix-store on next boot. 142 $machine->copyFileFromHost( 143 "${ makeConfig { inherit bootLoader grubVersion grubDevice grubIdentifier extraConfig; forceGrubReinstallCount = 1; } }", 144 "/etc/nixos/configuration.nix"); 145 146 # Check whether nixos-rebuild works. 147 $machine->succeed("nixos-rebuild switch >&2"); 148 149 # Test nixos-option. 150 $machine->succeed("nixos-option boot.initrd.kernelModules | grep virtio_console"); 151 $machine->succeed("nixos-option boot.initrd.kernelModules | grep 'List of modules'"); 152 $machine->succeed("nixos-option boot.initrd.kernelModules | grep qemu-guest.nix"); 153 154 $machine->shutdown; 155 156 # Check whether a writable store build works 157 $machine = createMachine({ ${hdFlags} qemuFlags => "${qemuFlags}", name => "rebuild-switch" }); 158 ${preBootCommands} 159 $machine->waitForUnit("multi-user.target"); 160 $machine->copyFileFromHost( 161 "${ makeConfig { inherit bootLoader grubVersion grubDevice grubIdentifier extraConfig; forceGrubReinstallCount = 2; } }", 162 "/etc/nixos/configuration.nix"); 163 $machine->succeed("nixos-rebuild boot >&2"); 164 $machine->shutdown; 165 166 # And just to be sure, check that the machine still boots after 167 # "nixos-rebuild switch". 168 $machine = createMachine({ ${hdFlags} qemuFlags => "${qemuFlags}", "boot-after-rebuild-switch" }); 169 ${preBootCommands} 170 $machine->waitForUnit("network.target"); 171 $machine->shutdown; 172 ''; 173 174 175 makeInstallerTest = name: 176 { createPartitions, preBootCommands ? "", extraConfig ? "" 177 , extraInstallerConfig ? {} 178 , bootLoader ? "grub" # either "grub" or "systemd-boot" 179 , grubVersion ? 2, grubDevice ? "/dev/vda", grubIdentifier ? "uuid" 180 , enableOCR ? false, meta ? {} 181 }: 182 makeTest { 183 inherit enableOCR; 184 name = "installer-" + name; 185 meta = with pkgs.stdenv.lib.maintainers; { 186 # put global maintainers here, individuals go into makeInstallerTest fkt call 187 maintainers = [ wkennington ] ++ (meta.maintainers or []); 188 }; 189 nodes = { 190 191 # The configuration of the machine used to run "nixos-install". It 192 # also has a web server that simulates cache.nixos.org. 193 machine = 194 { config, lib, pkgs, ... }: 195 196 { imports = 197 [ ../modules/profiles/installation-device.nix 198 ../modules/profiles/base.nix 199 extraInstallerConfig 200 ]; 201 202 virtualisation.diskSize = 8 * 1024; 203 virtualisation.memorySize = 1024; 204 virtualisation.writableStore = true; 205 206 # Use a small /dev/vdb as the root disk for the 207 # installer. This ensures the target disk (/dev/vda) is 208 # the same during and after installation. 209 virtualisation.emptyDiskImages = [ 512 ]; 210 virtualisation.bootDevice = 211 if grubVersion == 1 then "/dev/sdb" else "/dev/vdb"; 212 virtualisation.qemu.diskInterface = 213 if grubVersion == 1 then "scsi" else "virtio"; 214 215 boot.loader.systemd-boot.enable = mkIf (bootLoader == "systemd-boot") true; 216 217 hardware.enableAllFirmware = mkForce false; 218 219 # The test cannot access the network, so any packages we 220 # need must be included in the VM. 221 system.extraDependencies = with pkgs; 222 [ sudo 223 libxml2.bin 224 libxslt.bin 225 docbook5 226 docbook5_xsl 227 unionfs-fuse 228 ntp 229 nixos-artwork.wallpapers.gnome-dark 230 perlPackages.XMLLibXML 231 perlPackages.ListCompare 232 233 # add curl so that rather than seeing the test attempt to download 234 # curl's tarball, we see what it's trying to download 235 curl 236 ] 237 ++ optional (bootLoader == "grub" && grubVersion == 1) pkgs.grub 238 ++ optionals (bootLoader == "grub" && grubVersion == 2) [ pkgs.grub2 pkgs.grub2_efi ]; 239 240 nix.binaryCaches = mkForce [ ]; 241 }; 242 243 }; 244 245 testScript = testScriptFun { 246 inherit bootLoader createPartitions preBootCommands 247 grubVersion grubDevice grubIdentifier extraConfig; 248 }; 249 }; 250 251 252in { 253 254 # !!! `parted mkpart' seems to silently create overlapping partitions. 255 256 257 # The (almost) simplest partitioning scheme: a swap partition and 258 # one big filesystem partition. 259 simple = makeInstallerTest "simple" 260 { createPartitions = 261 '' 262 $machine->succeed( 263 "parted /dev/vda mklabel msdos", 264 "parted /dev/vda -- mkpart primary linux-swap 1M 1024M", 265 "parted /dev/vda -- mkpart primary ext2 1024M -1s", 266 "udevadm settle", 267 "mkswap /dev/vda1 -L swap", 268 "swapon -L swap", 269 "mkfs.ext3 -L nixos /dev/vda2", 270 "mount LABEL=nixos /mnt", 271 ); 272 ''; 273 }; 274 275 # Simple GPT/UEFI configuration using systemd-boot with 3 partitions: ESP, swap & root filesystem 276 simpleUefiSystemdBoot = makeInstallerTest "simpleUefiSystemdBoot" 277 { createPartitions = 278 '' 279 $machine->succeed( 280 "parted /dev/vda mklabel gpt", 281 "parted -s /dev/vda -- mkpart ESP fat32 1M 50MiB", # /boot 282 "parted -s /dev/vda -- set 1 boot on", 283 "parted -s /dev/vda -- mkpart primary linux-swap 50MiB 1024MiB", 284 "parted -s /dev/vda -- mkpart primary ext2 1024MiB -1MiB", # / 285 "udevadm settle", 286 "mkswap /dev/vda2 -L swap", 287 "swapon -L swap", 288 "mkfs.ext3 -L nixos /dev/vda3", 289 "mount LABEL=nixos /mnt", 290 "mkfs.vfat -n BOOT /dev/vda1", 291 "mkdir -p /mnt/boot", 292 "mount LABEL=BOOT /mnt/boot", 293 ); 294 ''; 295 bootLoader = "systemd-boot"; 296 }; 297 298 # Same as the previous, but now with a separate /boot partition. 299 separateBoot = makeInstallerTest "separateBoot" 300 { createPartitions = 301 '' 302 $machine->succeed( 303 "parted /dev/vda mklabel msdos", 304 "parted /dev/vda -- mkpart primary ext2 1M 50MB", # /boot 305 "parted /dev/vda -- mkpart primary linux-swap 50MB 1024M", 306 "parted /dev/vda -- mkpart primary ext2 1024M -1s", # / 307 "udevadm settle", 308 "mkswap /dev/vda2 -L swap", 309 "swapon -L swap", 310 "mkfs.ext3 -L nixos /dev/vda3", 311 "mount LABEL=nixos /mnt", 312 "mkfs.ext3 -L boot /dev/vda1", 313 "mkdir -p /mnt/boot", 314 "mount LABEL=boot /mnt/boot", 315 ); 316 ''; 317 }; 318 319 # Same as the previous, but with fat32 /boot. 320 separateBootFat = makeInstallerTest "separateBootFat" 321 { createPartitions = 322 '' 323 $machine->succeed( 324 "parted /dev/vda mklabel msdos", 325 "parted /dev/vda -- mkpart primary ext2 1M 50MB", # /boot 326 "parted /dev/vda -- mkpart primary linux-swap 50MB 1024M", 327 "parted /dev/vda -- mkpart primary ext2 1024M -1s", # / 328 "udevadm settle", 329 "mkswap /dev/vda2 -L swap", 330 "swapon -L swap", 331 "mkfs.ext3 -L nixos /dev/vda3", 332 "mount LABEL=nixos /mnt", 333 "mkfs.vfat -n BOOT /dev/vda1", 334 "mkdir -p /mnt/boot", 335 "mount LABEL=BOOT /mnt/boot", 336 ); 337 ''; 338 }; 339 340 # zfs on / with swap 341 zfsroot = makeInstallerTest "zfs-root" 342 { 343 extraInstallerConfig = { 344 boot.supportedFilesystems = [ "zfs" ]; 345 }; 346 347 extraConfig = '' 348 boot.supportedFilesystems = [ "zfs" ]; 349 350 # Using by-uuid overrides the default of by-id, and is unique 351 # to the qemu disks, as they don't produce by-id paths for 352 # some reason. 353 boot.zfs.devNodes = "/dev/disk/by-uuid/"; 354 networking.hostId = "00000000"; 355 ''; 356 357 createPartitions = 358 '' 359 $machine->succeed( 360 "parted /dev/vda mklabel msdos", 361 "parted /dev/vda -- mkpart primary linux-swap 1M 1024M", 362 "parted /dev/vda -- mkpart primary 1024M -1s", 363 "udevadm settle", 364 365 "mkswap /dev/vda1 -L swap", 366 "swapon -L swap", 367 368 "zpool create rpool /dev/vda2", 369 "zfs create -o mountpoint=legacy rpool/root", 370 "mount -t zfs rpool/root /mnt", 371 372 "udevadm settle" 373 ); 374 ''; 375 }; 376 377 # Create two physical LVM partitions combined into one volume group 378 # that contains the logical swap and root partitions. 379 lvm = makeInstallerTest "lvm" 380 { createPartitions = 381 '' 382 $machine->succeed( 383 "parted /dev/vda mklabel msdos", 384 "parted /dev/vda -- mkpart primary 1M 2048M", # PV1 385 "parted /dev/vda -- set 1 lvm on", 386 "parted /dev/vda -- mkpart primary 2048M -1s", # PV2 387 "parted /dev/vda -- set 2 lvm on", 388 "udevadm settle", 389 "pvcreate /dev/vda1 /dev/vda2", 390 "vgcreate MyVolGroup /dev/vda1 /dev/vda2", 391 "lvcreate --size 1G --name swap MyVolGroup", 392 "lvcreate --size 2G --name nixos MyVolGroup", 393 "mkswap -f /dev/MyVolGroup/swap -L swap", 394 "swapon -L swap", 395 "mkfs.xfs -L nixos /dev/MyVolGroup/nixos", 396 "mount LABEL=nixos /mnt", 397 ); 398 ''; 399 }; 400 401 # Boot off an encrypted root partition 402 luksroot = makeInstallerTest "luksroot" 403 { createPartitions = '' 404 $machine->succeed( 405 "parted /dev/vda mklabel msdos", 406 "parted /dev/vda -- mkpart primary ext2 1M 50MB", # /boot 407 "parted /dev/vda -- mkpart primary linux-swap 50M 1024M", 408 "parted /dev/vda -- mkpart primary 1024M -1s", # LUKS 409 "udevadm settle", 410 "mkswap /dev/vda2 -L swap", 411 "swapon -L swap", 412 "modprobe dm_mod dm_crypt", 413 "echo -n supersecret | cryptsetup luksFormat -q /dev/vda3 -", 414 "echo -n supersecret | cryptsetup luksOpen --key-file - /dev/vda3 cryptroot", 415 "mkfs.ext3 -L nixos /dev/mapper/cryptroot", 416 "mount LABEL=nixos /mnt", 417 "mkfs.ext3 -L boot /dev/vda1", 418 "mkdir -p /mnt/boot", 419 "mount LABEL=boot /mnt/boot", 420 ); 421 ''; 422 extraConfig = '' 423 boot.kernelParams = lib.mkAfter [ "console=tty0" ]; 424 ''; 425 enableOCR = true; 426 preBootCommands = '' 427 $machine->start; 428 $machine->waitForText(qr/Enter passphrase/); 429 $machine->sendChars("supersecret\n"); 430 ''; 431 }; 432 433 swraid = makeInstallerTest "swraid" 434 { createPartitions = 435 '' 436 $machine->succeed( 437 "parted /dev/vda --" 438 . " mklabel msdos" 439 . " mkpart primary ext2 1M 100MB" # /boot 440 . " mkpart extended 100M -1s" 441 . " mkpart logical 102M 1602M" # md0 (root), first device 442 . " mkpart logical 1603M 3103M" # md0 (root), second device 443 . " mkpart logical 3104M 3360M" # md1 (swap), first device 444 . " mkpart logical 3361M 3617M", # md1 (swap), second device 445 "udevadm settle", 446 "ls -l /dev/vda* >&2", 447 "cat /proc/partitions >&2", 448 "mdadm --create --force /dev/md0 --metadata 1.2 --level=raid1 --raid-devices=2 /dev/vda5 /dev/vda6", 449 "mdadm --create --force /dev/md1 --metadata 1.2 --level=raid1 --raid-devices=2 /dev/vda7 /dev/vda8", 450 "udevadm settle", 451 "mkswap -f /dev/md1 -L swap", 452 "swapon -L swap", 453 "mkfs.ext3 -L nixos /dev/md0", 454 "mount LABEL=nixos /mnt", 455 "mkfs.ext3 -L boot /dev/vda1", 456 "mkdir /mnt/boot", 457 "mount LABEL=boot /mnt/boot", 458 "udevadm settle", 459 ); 460 ''; 461 preBootCommands = '' 462 $machine->start; 463 $machine->fail("dmesg | grep 'immediate safe mode'"); 464 ''; 465 }; 466 467 # Test a basic install using GRUB 1. 468 grub1 = makeInstallerTest "grub1" 469 { createPartitions = 470 '' 471 $machine->succeed( 472 "parted /dev/sda mklabel msdos", 473 "parted /dev/sda -- mkpart primary linux-swap 1M 1024M", 474 "parted /dev/sda -- mkpart primary ext2 1024M -1s", 475 "udevadm settle", 476 "mkswap /dev/sda1 -L swap", 477 "swapon -L swap", 478 "mkfs.ext3 -L nixos /dev/sda2", 479 "mount LABEL=nixos /mnt", 480 ); 481 ''; 482 grubVersion = 1; 483 grubDevice = "/dev/sda"; 484 }; 485 486 # Test using labels to identify volumes in grub 487 simpleLabels = makeInstallerTest "simpleLabels" { 488 createPartitions = '' 489 $machine->succeed( 490 "sgdisk -Z /dev/vda", 491 "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", 492 "mkswap /dev/vda2 -L swap", 493 "swapon -L swap", 494 "mkfs.ext4 -L root /dev/vda3", 495 "mount LABEL=root /mnt", 496 ); 497 ''; 498 grubIdentifier = "label"; 499 }; 500 501 # Test using the provided disk name within grub 502 # TODO: Fix udev so the symlinks are unneeded in /dev/disks 503 simpleProvided = makeInstallerTest "simpleProvided" { 504 createPartitions = '' 505 my $UUID = "\$(blkid -s UUID -o value /dev/vda2)"; 506 $machine->succeed( 507 "sgdisk -Z /dev/vda", 508 "sgdisk -n 1:0:+1M -n 2:0:+100M -n 3:0:+1G -N 4 -t 1:ef02 -t 2:8300 -t 3:8200 -t 4:8300 -c 2:boot -c 4:root /dev/vda", 509 "mkswap /dev/vda3 -L swap", 510 "swapon -L swap", 511 "mkfs.ext4 -L boot /dev/vda2", 512 "mkfs.ext4 -L root /dev/vda4", 513 ); 514 $machine->execute("ln -s ../../vda2 /dev/disk/by-uuid/$UUID"); 515 $machine->execute("ln -s ../../vda4 /dev/disk/by-label/root"); 516 $machine->succeed( 517 "mount /dev/disk/by-label/root /mnt", 518 "mkdir /mnt/boot", 519 "mount /dev/disk/by-uuid/$UUID /mnt/boot" 520 ); 521 ''; 522 grubIdentifier = "provided"; 523 }; 524 525 # Simple btrfs grub testing 526 btrfsSimple = makeInstallerTest "btrfsSimple" { 527 createPartitions = '' 528 $machine->succeed( 529 "sgdisk -Z /dev/vda", 530 "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", 531 "mkswap /dev/vda2 -L swap", 532 "swapon -L swap", 533 "mkfs.btrfs -L root /dev/vda3", 534 "mount LABEL=root /mnt", 535 ); 536 ''; 537 }; 538 539 # Test to see if we can detect /boot and /nix on subvolumes 540 btrfsSubvols = makeInstallerTest "btrfsSubvols" { 541 createPartitions = '' 542 $machine->succeed( 543 "sgdisk -Z /dev/vda", 544 "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", 545 "mkswap /dev/vda2 -L swap", 546 "swapon -L swap", 547 "mkfs.btrfs -L root /dev/vda3", 548 "btrfs device scan", 549 "mount LABEL=root /mnt", 550 "btrfs subvol create /mnt/boot", 551 "btrfs subvol create /mnt/nixos", 552 "btrfs subvol create /mnt/nixos/default", 553 "umount /mnt", 554 "mount -o defaults,subvol=nixos/default LABEL=root /mnt", 555 "mkdir /mnt/boot", 556 "mount -o defaults,subvol=boot LABEL=root /mnt/boot", 557 ); 558 ''; 559 }; 560 561 # Test to see if we can detect default and aux subvolumes correctly 562 btrfsSubvolDefault = makeInstallerTest "btrfsSubvolDefault" { 563 createPartitions = '' 564 $machine->succeed( 565 "sgdisk -Z /dev/vda", 566 "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", 567 "mkswap /dev/vda2 -L swap", 568 "swapon -L swap", 569 "mkfs.btrfs -L root /dev/vda3", 570 "btrfs device scan", 571 "mount LABEL=root /mnt", 572 "btrfs subvol create /mnt/badpath", 573 "btrfs subvol create /mnt/badpath/boot", 574 "btrfs subvol create /mnt/nixos", 575 "btrfs subvol set-default \$(btrfs subvol list /mnt | grep 'nixos' | awk '{print \$2}') /mnt", 576 "umount /mnt", 577 "mount -o defaults LABEL=root /mnt", 578 "mkdir -p /mnt/badpath/boot", # Help ensure the detection mechanism is actually looking up subvolumes 579 "mkdir /mnt/boot", 580 "mount -o defaults,subvol=badpath/boot LABEL=root /mnt/boot", 581 ); 582 ''; 583 }; 584 585}