# The appliance image: boot the raw disk image under UEFI and check what makes # it an appliance (read-only verity store, volatile root, persistent /var) while # the router itself runs. { self, pkgs }: let common = import ./common.nix; in pkgs.testers.runNixOSTest { name = "router-image"; nodes.machine = { lib, ... }: { imports = [ self.nixosModules.router self.nixosModules.image common.tools ]; # The VM boots the image's own disk, not the usual test plumbing. virtualisation.fileSystems = lib.mkVMOverride { }; virtualisation.directBoot.enable = false; virtualisation.mountHostNixStore = false; virtualisation.useEFIBoot = true; virtualisation.vlans = [ 1 2 ]; networking.interfaces.eth1.ipv4.addresses = lib.mkForce [ ]; networking.interfaces.eth2.ipv4.addresses = lib.mkForce [ ]; system.image.version = "1"; router = { enable = true; wan.interface = "eth1"; lans.main = { interface = "eth2"; internet = true; ipv4.address = "192.168.10.1"; dhcp.pool = { start = "192.168.10.100"; end = "192.168.10.199"; }; }; }; }; testScript = { nodes, ... }: '' import os import subprocess import tempfile disk = tempfile.NamedTemporaryFile() subprocess.run([ "${nodes.machine.virtualisation.qemu.package}/bin/qemu-img", "create", "-f", "qcow2", "-b", "${nodes.machine.system.build.image}/${nodes.machine.image.filePath}", "-F", "raw", disk.name, ], check=True) os.environ["NIX_DISK_IMAGE"] = disk.name machine.wait_for_unit("multi-user.target") with subtest("the disk has the appliance layout"): parts = machine.succeed("lsblk -n -o PARTLABEL /dev/vda") for label in ("esp", "store-verity", "store", "state"): assert label in parts, parts with subtest("root is volatile and /nix/store is a dm-verity protected read-only partition"): machine.succeed("findmnt --kernel --type tmpfs /") assert "ACTIVE" in machine.succeed("dmsetup info --target verity usr") backing = machine.succeed("df --output=source /nix/store | tail -n1").strip() assert backing == "/dev/mapper/usr", backing machine.fail("touch /nix/store/should-not-work") machine.fail("touch /etc/should-not-work") with subtest("the image identifies itself"): machine.succeed("grep -qE '^IMAGE_VERSION=.?1.?$' /etc/os-release") machine.succeed("grep -qE '^IMAGE_ID=.?nixos-router.?$' /etc/os-release") with subtest("the router comes up from the image"): machine.wait_for_unit("nftables.service") machine.wait_for_unit("unbound.service") machine.wait_for_unit("kea-dhcp4-server.service") machine.wait_until_succeeds("ip -4 addr show dev eth2 | grep -q 192.168.10.1") with subtest("there is no Nix on the device"): machine.fail("command -v nix-env") with subtest("/var is on the state partition and survives a reboot, the root does not"): src = machine.succeed("findmnt -n -o SOURCE /var").strip() assert "vda" in src, src machine.succeed("echo kept > /var/lib/marker; echo lost > /root/marker; sync") machine.shutdown() machine.start() machine.wait_for_unit("multi-user.target") assert machine.succeed("cat /var/lib/marker").strip() == "kept" machine.fail("test -e /root/marker") machine.wait_for_unit("nftables.service") ''; }