summaryrefslogtreecommitdiffstats
path: root/tests/lib.nix
blob: fb9d1e901e84491cf29c003c9e9399f4a2d75765 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
{ pkgs ? (import <nixpkgs> { })
, makeTest ? import <nixpkgs/nixos/tests/make-test-python.nix>
, eval-config ? import <nixpkgs/nixos/lib/eval-config.nix>
, ...
}:
{
  makeDiskoTest =
    { disko-config
    , extraTestScript ? ""
    , bootCommands ? ""
    , extraConfig ? { }
    , grub-devices ? [ "nodev" ]
    , efi ? true
    , enableOCR ? false
    }:
    let
      lib = pkgs.lib;
      makeTest' = args:
        makeTest args {
          inherit pkgs;
          inherit (pkgs) system;
        };
      disks = [ "/dev/vda" "/dev/vdb" "/dev/vdc" "/dev/vdd" "/dev/vde" "/dev/vdf" ];
      tsp-create = pkgs.writeScript "create" ((pkgs.callPackage ../. { }).create (disko-config { disks = builtins.tail disks; }));
      tsp-mount = pkgs.writeScript "mount" ((pkgs.callPackage ../. { }).mount (disko-config { disks = builtins.tail disks; }));
      tsp-config = (pkgs.callPackage ../. { }).config (disko-config { inherit disks; });
      num-disks = builtins.length (lib.attrNames (disko-config {}).disk);
      installed-system = { modulesPath, ... }: {
        imports = [
          tsp-config
          (modulesPath + "/testing/test-instrumentation.nix")
          (modulesPath + "/profiles/qemu-guest.nix")
          (modulesPath + "/profiles/minimal.nix")
          extraConfig
        ];
        fileSystems."/nix/store" = {
          device = "nix-store";
          fsType = "9p";
          neededForBoot = true;
          options = [ "trans=virtio" "version=9p2000.L" "cache=loose" ];
        };
        documentation.enable = false;
        hardware.enableAllFirmware = lib.mkForce false;
        networking.hostId = "8425e349"; # from profiles/base.nix, needed for zfs
        boot.kernelParams = lib.mkAfter [ "console=tty0" ]; # needed to have serial interaction during boot
        boot.zfs.devNodes = "/dev/disk/by-uuid"; # needed because /dev/disk/by-id is empty in qemu-vms

        boot.consoleLogLevel = lib.mkForce 100;
        boot.loader.grub = {
          devices = grub-devices;
          efiSupport = efi;
          efiInstallAsRemovable = efi;
        };
      };
      installedTopLevel = (eval-config {
        modules = [ installed-system ];
        system = "x86_64-linux";
      }).config.system.build.toplevel;
    in
    makeTest' {
      name = "disko";

      inherit enableOCR;
      nodes.machine = { config, pkgs, modulesPath, ... }: {
        imports = [
          (modulesPath + "/profiles/base.nix")
          (modulesPath + "/profiles/minimal.nix")
          extraConfig
        ];

        # speed-up eval
        documentation.enable = false;

        nix.settings = {
          substituters = lib.mkForce [];
          hashed-mirrors = null;
          connect-timeout = 1;
        };

        virtualisation.emptyDiskImages = builtins.genList (_: 4096) num-disks;
      };

      testScript = ''
        def disks(oldmachine, num_disks):
            disk_flags = ""
            for i in range(num_disks):
                disk_flags += f' -drive file={oldmachine.state_dir}/empty{i}.qcow2,id=drive{i + 1},if=none,index={i + 1},werror=report'
                disk_flags += f' -device virtio-blk-pci,drive=drive{i + 1}'
            return disk_flags
        def create_test_machine(oldmachine=None, args={}): # taken from <nixpkgs/nixos/tests/installer.nix>
            machine = create_machine({
              "qemuFlags": "-cpu max -m 1024 -virtfs local,path=/nix/store,security_model=none,mount_tag=nix-store" + disks(oldmachine, ${toString num-disks}),
              ${lib.optionalString efi ''"bios": "${pkgs.OVMF.fd}/FV/OVMF.fd",''}
            } | args)
            driver.machines.append(machine)
            return machine

        machine.start()
        machine.succeed("echo -n 'secret' > /tmp/secret.key")
        machine.succeed("${tsp-create}")
        machine.succeed("${tsp-mount}")
        machine.succeed("${tsp-mount}") # verify that the command is idempotent

        # mount nix-store in /mnt
        machine.succeed("mkdir -p /mnt/nix/store")
        machine.succeed("mount --bind /nix/store /mnt/nix/store")

        machine.succeed("nix-store --load-db < ${pkgs.closureInfo {rootPaths = [installedTopLevel];}}/registration")

        # fix "this is not a NixOS installation"
        machine.succeed("mkdir -p /mnt/etc")
        machine.succeed("touch /mnt/etc/NIXOS")

        machine.succeed("mkdir -p /mnt/nix/var/nix/profiles")
        machine.succeed("nix-env -p /mnt/nix/var/nix/profiles/system --set ${installedTopLevel}")
        machine.succeed("NIXOS_INSTALL_BOOTLOADER=1 nixos-enter --root /mnt -- ${installedTopLevel}/bin/switch-to-configuration boot")
        machine.succeed("sync")
        machine.shutdown()

        machine = create_test_machine(oldmachine=machine, args={ "name": "booted_machine" })
        machine.start()
        ${bootCommands}
        machine.wait_for_unit("local-fs.target")
        ${extraTestScript}
      '';
    };
}