# router-install: an installer VM writes a router system to an empty disk # (/dev/vda), then a second VM boots that disk with UEFI and the installed # router must come up, with its secrets in place. # # Follows nixos/tests/installer.nix: both machines share one disk image; the # installer runs from a small second disk. { self, pkgs }: let inherit (pkgs) lib; common = import ./common.nix; # The system to install: a minimal router on the layout the installer creates. target = import "${pkgs.path}/nixos/lib/eval-config.nix" { system = "x86_64-linux"; modules = [ self.nixosModules.router self.nixosModules.installed-layout # Only so the test driver can talk to the installed system. "${pkgs.path}/nixos/modules/testing/test-instrumentation.nix" { system.stateVersion = "25.05"; users.users.root.openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFakeKeyForTestsOnlyXXXXXXXXXXXXXXXXXXXXXXXXXX test" ]; 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"; }; }; }; } ]; }; toplevel = target.config.system.build.toplevel; # Both machines must see the same disk. sharedDisk = { virtualisation.diskImage = "./target.qcow2"; virtualisation.diskSize = 6144; virtualisation.memorySize = 2048; }; in pkgs.testers.runNixOSTest { name = "router-installer"; nodes = { installer = { lib, ... }: { imports = [ sharedDisk self.nixosModules.installer common.tools ]; router.installer.system = toplevel; # Run from a small second disk so /dev/vda is the target. virtualisation.fileSystems."/".autoFormat = true; virtualisation.emptyDiskImages = [ 1024 ]; virtualisation.rootDevice = "/dev/vdb"; # No network in the sandbox; everything needed is in the closure. nix.settings.substituters = lib.mkForce [ ]; }; target = { imports = [ sharedDisk ]; virtualisation.vlans = [ 1 2 ]; virtualisation.useBootLoader = true; virtualisation.useEFIBoot = true; virtualisation.useDefaultFilesystems = false; virtualisation.efi.keepVariables = false; virtualisation.fileSystems."/" = { device = "/dev/disk/by-label/this-is-not-real-and-will-never-be-used"; fsType = "ext4"; }; }; }; testScript = '' installer.start() installer.wait_for_unit("multi-user.target") with subtest("router-install refuses bad input"): installer.fail("router-install") installer.fail("router-install --yes /etc/hostname") # The installer's own root disk is mounted. out = installer.fail("router-install --yes /dev/vdb 2>&1") assert "mounted" in out, out installer.fail("router-install --yes --secrets /nonexistent /dev/vda") # Nothing was touched. installer.fail("blkid /dev/vda1") with subtest("installation onto the empty disk"): installer.succeed("mkdir -p /root/secrets && echo -n hunter2 > /root/secrets/pppoe-password") installer.succeed("router-install --yes --secrets /root/secrets /dev/vda >&2") # Layout contract with the installed-layout module. assert "boot" in installer.succeed("blkid -s LABEL -o value /dev/vda1") assert "nixos" in installer.succeed("blkid -s LABEL -o value /dev/vda2") installer.shutdown() # The same machine, booting from the installed disk this time. target.state_dir = installer.state_dir target.start() with subtest("the installed system boots and runs the router"): target.wait_for_unit("multi-user.target") assert target.succeed("readlink -f /run/current-system").strip() == "${toplevel}" target.succeed("findmnt /boot | grep -q vfat") target.succeed("test -e /boot/EFI/BOOT/BOOTX64.EFI") target.wait_for_unit("nftables.service") target.wait_for_unit("unbound.service") target.wait_for_unit("kea-dhcp4-server.service") target.wait_until_succeeds("ip -4 addr show dev eth2 | grep -q 192.168.10.1") target.succeed("command -v router-arm router-confirm") with subtest("secrets arrive with strict permissions"): assert target.succeed("cat /var/lib/router/pppoe-password") == "hunter2" assert target.succeed("stat -c %a /var/lib/router").strip() == "700" assert target.succeed("stat -c %a /var/lib/router/pppoe-password").strip() == "600" assert target.succeed("stat -c %U /var/lib/router/pppoe-password").strip() == "root" ''; }