diff --git a/nixos/modules/virtualisation/incus.nix b/nixos/modules/virtualisation/incus.nix index aa2102f49f0d..4292662a9152 100644 --- a/nixos/modules/virtualisation/incus.nix +++ b/nixos/modules/virtualisation/incus.nix @@ -108,6 +108,10 @@ let name = "OVMF_VARS.4MB.ms.fd"; path = "${pkgs.OVMFFull.fd}/FV/${ovmf-prefix}_VARS.fd"; } + { + name = "seabios.bin"; + path = "${pkgs.seabios-qemu}/share/seabios/bios.bin"; + } ]; environment = lib.mkMerge [ diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 0b30f3cd3efb..92033b7c58f6 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -467,8 +467,8 @@ in { iftop = handleTest ./iftop.nix {}; immich = handleTest ./web-apps/immich.nix {}; incron = handleTest ./incron.nix {}; - incus = pkgs.recurseIntoAttrs (handleTest ./incus { inherit handleTestOn; inherit (pkgs) incus; }); - incus-lts = pkgs.recurseIntoAttrs (handleTest ./incus { inherit handleTestOn; }); + incus = pkgs.recurseIntoAttrs (handleTest ./incus { lts = false; }); + incus-lts = pkgs.recurseIntoAttrs (handleTest ./incus { }); influxdb = handleTest ./influxdb.nix {}; influxdb2 = handleTest ./influxdb2.nix {}; initrd-network-openvpn = handleTestOn [ "x86_64-linux" "i686-linux" ] ./initrd-network-openvpn {}; diff --git a/nixos/tests/incus/container.nix b/nixos/tests/incus/container.nix deleted file mode 100644 index bed5b579a40c..000000000000 --- a/nixos/tests/incus/container.nix +++ /dev/null @@ -1,154 +0,0 @@ -import ../make-test-python.nix ( - { - pkgs, - lib, - extra ? { }, - name ? "incus-container", - incus ? pkgs.incus-lts, - ... - }: - - let - releases = import ../../release.nix { - configuration = lib.recursiveUpdate { - # Building documentation makes the test unnecessarily take a longer time: - documentation.enable = lib.mkForce false; - - boot.kernel.sysctl."net.ipv4.ip_forward" = "1"; - } extra; - }; - - container-image-metadata = "${ - releases.incusContainerMeta.${pkgs.stdenv.hostPlatform.system} - }/tarball/nixos-image-lxc-*-${pkgs.stdenv.hostPlatform.system}.tar.xz"; - container-image-rootfs = "${ - releases.incusContainerImage.${pkgs.stdenv.hostPlatform.system} - }/nixos-lxc-image-${pkgs.stdenv.hostPlatform.system}.squashfs"; - in - { - inherit name; - - meta = { - maintainers = lib.teams.lxc.members; - }; - - nodes.machine = - { ... }: - { - virtualisation = { - # Ensure test VM has enough resources for creating and managing guests - cores = 2; - memorySize = 1024; - diskSize = 4096; - - incus = { - enable = true; - package = incus; - }; - }; - networking.nftables.enable = true; - }; - - testScript = # python - '' - def instance_is_up(_) -> bool: - status, _ = machine.execute("incus exec container --disable-stdin --force-interactive /run/current-system/sw/bin/systemctl -- is-system-running") - return status == 0 - - def set_container(config): - machine.succeed(f"incus config set container {config}") - machine.succeed("incus restart container") - with machine.nested("Waiting for instance to start and be usable"): - retry(instance_is_up) - - def check_sysctl(instance): - with subtest("systemd sysctl settings are applied"): - machine.succeed(f"incus exec {instance} -- systemctl status systemd-sysctl") - sysctl = machine.succeed(f"incus exec {instance} -- sysctl net.ipv4.ip_forward").strip().split(" ")[-1] - assert "1" == sysctl, f"systemd-sysctl configuration not correctly applied, {sysctl} != 1" - - machine.wait_for_unit("incus.service") - - # no preseed should mean no service - machine.fail("systemctl status incus-preseed.service") - - machine.succeed("incus admin init --minimal") - - with subtest("Container image can be imported"): - machine.succeed("incus image import ${container-image-metadata} ${container-image-rootfs} --alias nixos") - - with subtest("Container can be launched and managed"): - machine.succeed("incus launch nixos container") - with machine.nested("Waiting for instance to start and be usable"): - retry(instance_is_up) - machine.succeed("echo true | incus exec container /run/current-system/sw/bin/bash -") - - with subtest("Container mounts lxcfs overlays"): - machine.succeed("incus exec container mount | grep 'lxcfs on /proc/cpuinfo type fuse.lxcfs'") - machine.succeed("incus exec container mount | grep 'lxcfs on /proc/meminfo type fuse.lxcfs'") - - with subtest("resource limits"): - with subtest("Container CPU limits can be managed"): - set_container("limits.cpu 1") - cpuinfo = machine.succeed("incus exec container grep -- -c ^processor /proc/cpuinfo").strip() - assert cpuinfo == "1", f"Wrong number of CPUs reported from /proc/cpuinfo, want: 1, got: {cpuinfo}" - - set_container("limits.cpu 2") - cpuinfo = machine.succeed("incus exec container grep -- -c ^processor /proc/cpuinfo").strip() - assert cpuinfo == "2", f"Wrong number of CPUs reported from /proc/cpuinfo, want: 2, got: {cpuinfo}" - - with subtest("Container memory limits can be managed"): - set_container("limits.memory 64MB") - meminfo = machine.succeed("incus exec container grep -- MemTotal /proc/meminfo").strip() - meminfo_bytes = " ".join(meminfo.split(' ')[-2:]) - assert meminfo_bytes == "62500 kB", f"Wrong amount of memory reported from /proc/meminfo, want: '62500 kB', got: '{meminfo_bytes}'" - - set_container("limits.memory 128MB") - meminfo = machine.succeed("incus exec container grep -- MemTotal /proc/meminfo").strip() - meminfo_bytes = " ".join(meminfo.split(' ')[-2:]) - assert meminfo_bytes == "125000 kB", f"Wrong amount of memory reported from /proc/meminfo, want: '125000 kB', got: '{meminfo_bytes}'" - - with subtest("virtual tpm can be configured"): - machine.succeed("incus config device add container vtpm tpm path=/dev/tpm0 pathrm=/dev/tpmrm0") - machine.succeed("incus exec container -- test -e /dev/tpm0") - machine.succeed("incus exec container -- test -e /dev/tpmrm0") - machine.succeed("incus config device remove container vtpm") - machine.fail("incus exec container -- test -e /dev/tpm0") - - with subtest("lxc-generator"): - with subtest("lxc-container generator configures plain container"): - # reuse the existing container to save some time - machine.succeed("incus exec container test -- -e /run/systemd/system/service.d/zzz-lxc-service.conf") - check_sysctl("container") - - with subtest("lxc-container generator configures nested container"): - machine.execute("incus delete --force container") - machine.succeed("incus launch nixos container --config security.nesting=true") - with machine.nested("Waiting for instance to start and be usable"): - retry(instance_is_up) - - machine.fail("incus exec container test -- -e /run/systemd/system/service.d/zzz-lxc-service.conf") - target = machine.succeed("incus exec container readlink -- -f /run/systemd/system/systemd-binfmt.service").strip() - assert target == "/dev/null", "lxc generator did not correctly mask /run/systemd/system/systemd-binfmt.service" - - check_sysctl("container") - - with subtest("lxc-container generator configures privileged container"): - machine.execute("incus delete --force container") - machine.succeed("incus launch nixos container --config security.privileged=true") - with machine.nested("Waiting for instance to start and be usable"): - retry(instance_is_up) - - machine.succeed("incus exec container test -- -e /run/systemd/system/service.d/zzz-lxc-service.conf") - - check_sysctl("container") - - with subtest("softDaemonRestart"): - with subtest("Instance remains running when softDaemonRestart is enabled and services is stopped"): - pid = machine.succeed("incus info container | grep 'PID'").split(":")[1].strip() - machine.succeed(f"ps {pid}") - machine.succeed("systemctl stop incus") - machine.succeed(f"ps {pid}") - ''; - } -) diff --git a/nixos/tests/incus/default.nix b/nixos/tests/incus/default.nix index c33bf1600f27..525b07ae2948 100644 --- a/nixos/tests/incus/default.nix +++ b/nixos/tests/incus/default.nix @@ -1,29 +1,42 @@ { - system ? builtins.currentSystem, - config ? { }, - pkgs ? import ../../.. { inherit system config; }, - handleTestOn, - incus ? pkgs.incus-lts, + lts ? true, + ... }: +let + incusTest = import ./incus-tests.nix; +in { - container-legacy-init = import ./container.nix { - name = "container-legacy-init"; - inherit incus system pkgs; + all = incusTest { + inherit lts; + allTests = true; }; - container-systemd-init = import ./container.nix { - name = "container-systemd-init"; - inherit incus system pkgs; - extra = { - boot.initrd.systemd.enable = true; - }; + + container = incusTest { + inherit lts; + instanceContainer = true; }; - incusd-options = import ./incusd-options.nix { inherit incus system pkgs; }; - lxd-to-incus = import ./lxd-to-incus.nix { inherit incus system pkgs; }; - openvswitch = import ./openvswitch.nix { inherit incus system pkgs; }; - socket-activated = import ./socket-activated.nix { inherit incus system pkgs; }; - storage = import ./storage.nix { inherit incus system pkgs; }; - ui = import ./ui.nix { inherit incus system pkgs; }; - virtual-machine = handleTestOn [ "x86_64-linux" ] ./virtual-machine.nix { - inherit incus system pkgs; + + lvm = incusTest { + inherit lts; + storageLvm = true; + }; + + lxd-to-incus = import ./lxd-to-incus.nix { }; + + openvswitch = incusTest { + inherit lts; + networkOvs = true; + }; + + ui = import ./ui.nix { }; + + virtual-machine = incusTest { + inherit lts; + instanceVm = true; + }; + + zfs = incusTest { + inherit lts; + storageLvm = true; }; } diff --git a/nixos/tests/incus/incus-tests.nix b/nixos/tests/incus/incus-tests.nix new file mode 100644 index 000000000000..fb4599058225 --- /dev/null +++ b/nixos/tests/incus/incus-tests.nix @@ -0,0 +1,452 @@ +import ../make-test-python.nix ( + { + pkgs, + lib, + + lts ? true, + + allTests ? false, + + featureUser ? allTests, + initLegacy ? true, + initSystemd ? true, + instanceContainer ? allTests, + instanceVm ? allTests, + networkOvs ? allTests, + storageLvm ? allTests, + storageZfs ? allTests, + ... + }: + + let + releases = + init: + import ../../release.nix { + configuration = { + # Building documentation makes the test unnecessarily take a longer time: + documentation.enable = lib.mkForce false; + + boot.initrd.systemd.enable = init == "systemd"; + + # Arbitrary sysctl modification to ensure containers can update sysctl + boot.kernel.sysctl."net.ipv4.ip_forward" = "1"; + }; + }; + + images = init: { + container = { + metadata = + (releases init).incusContainerMeta.${pkgs.stdenv.hostPlatform.system} + + "/tarball/nixos-image-lxc-*-${pkgs.stdenv.hostPlatform.system}.tar.xz"; + + rootfs = + (releases init).incusContainerImage.${pkgs.stdenv.hostPlatform.system} + + "/nixos-lxc-image-${pkgs.stdenv.hostPlatform.system}.squashfs"; + }; + + virtual-machine = { + metadata = + (releases init).incusVirtualMachineImageMeta.${pkgs.stdenv.hostPlatform.system} + "/*/*.tar.xz"; + disk = (releases init).incusVirtualMachineImage.${pkgs.stdenv.hostPlatform.system} + "/nixos.qcow2"; + }; + }; + + initVariants = lib.optionals initLegacy [ "legacy" ] ++ lib.optionals initSystemd [ "systemd" ]; + + canTestVm = instanceVm && pkgs.stdenv.isLinux && pkgs.stdenv.isx86_64; + in + { + name = "incus" + lib.optionalString lts "-lts"; + + meta = { + maintainers = lib.teams.lxc.members; + }; + + nodes.machine = { + virtualisation = { + cores = 2; + memorySize = 2048; + diskSize = 12 * 1024; + emptyDiskImages = [ + # vdb for zfs + 2048 + # vdc for lvm + 2048 + ]; + + incus = { + enable = true; + package = if lts then pkgs.incus-lts else pkgs.incus; + + preseed = { + networks = + [ + { + name = "incusbr0"; + type = "bridge"; + config = { + "ipv4.address" = "10.0.10.1/24"; + "ipv4.nat" = "true"; + }; + } + ] + ++ lib.optionals networkOvs [ + { + name = "ovsbr0"; + type = "bridge"; + config = { + "bridge.driver" = "openvswitch"; + "ipv4.address" = "10.0.20.1/24"; + "ipv4.nat" = "true"; + }; + } + ]; + profiles = [ + { + name = "default"; + devices = { + eth0 = { + name = "eth0"; + network = "incusbr0"; + type = "nic"; + }; + root = { + path = "/"; + pool = "default"; + size = "35GiB"; + type = "disk"; + }; + }; + } + ]; + storage_pools = [ + { + name = "default"; + driver = "dir"; + } + ]; + }; + }; + + vswitch.enable = networkOvs; + }; + + boot.supportedFilesystems = lib.optionals storageZfs [ "zfs" ]; + boot.zfs.forceImportRoot = false; + + environment.systemPackages = [ pkgs.parted ]; + + networking.hostId = "01234567"; + networking.firewall.trustedInterfaces = [ "incusbr0" ]; + + services.lvm = { + boot.thin.enable = storageLvm; + dmeventd.enable = storageLvm; + }; + + networking.nftables.enable = true; + + users.users.testuser = { + isNormalUser = true; + shell = pkgs.bashInteractive; + group = "incus"; + uid = 1000; + }; + }; + + testScript = # python + '' + import json + + def wait_for_instance(name: str, project: str = "default"): + machine.wait_until_succeeds(f"incus exec {name} --disable-stdin --force-interactive --project {project} -- /run/current-system/sw/bin/systemctl is-system-running") + + + def wait_incus_exec_success(name: str, command: str, timeout: int = 900, project: str = "default"): + def check_command(_) -> bool: + status, _ = machine.execute(f"incus exec {name} --disable-stdin --force-interactive --project {project} -- {command}") + return status == 0 + + with machine.nested(f"Waiting for successful exec: {command}"): + retry(check_command, timeout) + + + def set_config(name: str, config: str, restart: bool = False, unset: bool = False): + if restart: + machine.succeed(f"incus stop {name}") + + if unset: + machine.succeed(f"incus config unset {name} {config}") + else: + machine.succeed(f"incus config set {name} {config}") + + if restart: + machine.succeed(f"incus start {name}") + wait_for_instance(name) + else: + # give a moment to settle + machine.sleep(1) + + + def cleanup(): + # avoid conflict between preseed and cleanup operations + machine.wait_for_unit("incus-preseed.service") + + instances = json.loads(machine.succeed("incus list --format json --all-projects")) + with subtest("Stopping all running instances"): + for instance in [a for a in instances if a['status'] == 'Running']: + machine.execute(f"incus stop --force {instance['name']} --project {instance['project']}") + machine.execute(f"incus delete --force {instance['name']} --project {instance['project']}") + + + def check_sysctl(name: str): + with subtest("systemd sysctl settings are applied"): + machine.succeed(f"incus exec {name} -- systemctl status systemd-sysctl") + sysctl = machine.succeed(f"incus exec {name} -- sysctl net.ipv4.ip_forward").strip().split(" ")[-1] + assert "1" == sysctl, f"systemd-sysctl configuration not correctly applied, {sysctl} != 1" + + + with subtest("Wait for startup"): + machine.wait_for_unit("incus.service") + machine.wait_for_unit("incus-preseed.service") + + + with subtest("Verify preseed resources created"): + machine.succeed("incus profile show default") + machine.succeed("incus network info incusbr0") + machine.succeed("incus storage show default") + + '' + + lib.optionalString instanceContainer ( + lib.foldl ( + acc: variant: + acc + # python + + '' + metadata = "${(images variant).container.metadata}" + rootfs = "${(images variant).container.rootfs}" + alias = "nixos/container/${variant}" + variant = "${variant}" + + with subtest("Container image can be imported"): + machine.succeed(f"incus image import {metadata} {rootfs} --alias {alias}") + + + with subtest("Container can be launched and managed"): + machine.succeed(f"incus launch {alias} container-{variant}1") + wait_for_instance(f"container-{variant}1") + + + with subtest("Container mounts lxcfs overlays"): + machine.succeed(f"incus exec container-{variant}1 mount | grep 'lxcfs on /proc/cpuinfo type fuse.lxcfs'") + machine.succeed(f"incus exec container-{variant}1 mount | grep 'lxcfs on /proc/meminfo type fuse.lxcfs'") + + + with subtest("resource limits"): + with subtest("Container CPU limits can be managed"): + set_config(f"container-{variant}1", "limits.cpu 1", restart=True) + wait_incus_exec_success(f"container-{variant}1", "nproc | grep '^1$'", timeout=15) + + with subtest("Container CPU limits can be hotplug changed"): + set_config(f"container-{variant}1", "limits.cpu 2") + wait_incus_exec_success(f"container-{variant}1", "nproc | grep '^2$'", timeout=15) + + with subtest("Container memory limits can be managed"): + set_config(f"container-{variant}1", "limits.memory 128MB", restart=True) + wait_incus_exec_success(f"container-{variant}1", "grep 'MemTotal:[[:space:]]*125000 kB' /proc/meminfo", timeout=15) + + with subtest("Container memory limits can be hotplug changed"): + set_config(f"container-{variant}1", "limits.memory 256MB") + wait_incus_exec_success(f"container-{variant}1", "grep 'MemTotal:[[:space:]]*250000 kB' /proc/meminfo", timeout=15) + + + with subtest("virtual tpm can be configured"): + machine.succeed(f"incus config device add container-{variant}1 vtpm tpm path=/dev/tpm0 pathrm=/dev/tpmrm0") + machine.succeed(f"incus exec container-{variant}1 -- test -e /dev/tpm0") + machine.succeed(f"incus exec container-{variant}1 -- test -e /dev/tpmrm0") + machine.succeed(f"incus config device remove container-{variant}1 vtpm") + machine.fail(f"incus exec container-{variant}1 -- test -e /dev/tpm0") + + + with subtest("lxc-generator"): + with subtest("lxc-container generator configures plain container"): + # default container is plain + machine.succeed(f"incus exec container-{variant}1 test -- -e /run/systemd/system/service.d/zzz-lxc-service.conf") + + check_sysctl(f"container-{variant}1") + + with subtest("lxc-container generator configures nested container"): + set_config(f"container-{variant}1", "security.nesting=true", restart=True) + + machine.fail(f"incus exec container-{variant}1 test -- -e /run/systemd/system/service.d/zzz-lxc-service.conf") + target = machine.succeed(f"incus exec container-{variant}1 readlink -- -f /run/systemd/system/systemd-binfmt.service").strip() + assert target == "/dev/null", "lxc generator did not correctly mask /run/systemd/system/systemd-binfmt.service" + + check_sysctl(f"container-{variant}1") + + with subtest("lxc-container generator configures privileged container"): + # Create a new instance for a clean state + machine.succeed(f"incus launch {alias} container-{variant}2") + wait_for_instance(f"container-{variant}2") + + machine.succeed(f"incus exec container-{variant}2 test -- -e /run/systemd/system/service.d/zzz-lxc-service.conf") + + check_sysctl(f"container-{variant}2") + + + with subtest("Instance remains running when softDaemonRestart is enabled and service is stopped"): + pid = machine.succeed(f"incus info container-{variant}1 | grep 'PID'").split(":")[1].strip() + machine.succeed(f"ps {pid}") + machine.succeed("systemctl stop incus") + machine.succeed(f"ps {pid}") + machine.succeed("systemctl start incus") + + + cleanup() + '' + ) "" initVariants + ) + + lib.optionalString canTestVm ( + (lib.foldl ( + acc: variant: + acc + # python + + '' + metadata = "${(images variant).virtual-machine.metadata}" + disk = "${(images variant).virtual-machine.disk}" + alias = "nixos/virtual-machine/${variant}" + variant = "${variant}" + + with subtest("virtual-machine image can be imported"): + machine.succeed(f"incus image import {metadata} {disk} --alias {alias}") + + + with subtest("virtual-machine can be created"): + machine.succeed(f"incus create {alias} vm-{variant}1 --vm --config limits.memory=512MB --config security.secureboot=false") + + + with subtest("virtual tpm can be configured"): + machine.succeed(f"incus config device add vm-{variant}1 vtpm tpm path=/dev/tpm0") + + + with subtest("virtual-machine can be launched and become available"): + machine.succeed(f"incus start vm-{variant}1") + wait_for_instance(f"vm-{variant}1") + + + with subtest("incus-agent is started"): + machine.succeed(f"incus exec vm-{variant}1 systemctl is-active incus-agent") + + + with subtest("incus-agent has a valid path"): + machine.succeed(f"incus exec vm-{variant}1 -- bash -c 'true'") + + + with subtest("Container CPU limits can be managed"): + set_config(f"vm-{variant}1", "limits.cpu 1", restart=True) + wait_incus_exec_success(f"vm-{variant}1", "nproc | grep '^1$'", timeout=90) + + + with subtest("Container CPU limits can be hotplug changed"): + set_config(f"vm-{variant}1", "limits.cpu 2") + wait_incus_exec_success(f"vm-{variant}1", "nproc | grep '^2$'", timeout=15) + + + with subtest("Instance remains running when softDaemonRestart is enabled and service is stopped"): + pid = machine.succeed(f"incus info vm-{variant}1 | grep 'PID'").split(":")[1].strip() + machine.succeed(f"ps {pid}") + machine.succeed("systemctl stop incus") + machine.succeed(f"ps {pid}") + machine.succeed("systemctl start incus") + + + cleanup() + '' + ) "" initVariants) + + + # python + '' + with subtest("Can launch CSM virtual machine"): + machine.succeed("incus init csm --vm --empty -c security.csm=true -c security.secureboot=false") + machine.succeed("incus start csm") + + + cleanup() + '' + ) + + + lib.optionalString featureUser # python + '' + with subtest("incus-user allows restricted access for users"): + machine.fail("incus project show user-1000") + machine.succeed("su - testuser bash -c 'incus list'") + # a project is created dynamically for the user + machine.succeed("incus project show user-1000") + # users shouldn't be able to list storage pools + machine.fail("su - testuser bash -c 'incus storage list'") + + + with subtest("incus-user allows users to launch instances"): + machine.succeed("su - testuser bash -c 'incus image import ${(images "systemd").container.metadata} ${(images "systemd").container.rootfs} --alias nixos'") + machine.succeed("su - testuser bash -c 'incus launch nixos instance2'") + wait_for_instance("instance2", "user-1000") + + cleanup() + '' + + + lib.optionalString networkOvs # python + '' + with subtest("Verify openvswitch bridge"): + machine.succeed("incus network info ovsbr0") + + + with subtest("Verify openvswitch bridge"): + machine.succeed("ovs-vsctl br-exists ovsbr0") + '' + + + + lib.optionalString storageZfs # python + '' + with subtest("Verify zfs pool created and usable"): + machine.succeed( + "zpool status", + "parted --script /dev/vdb mklabel gpt", + "zpool create zfs_pool /dev/vdb", + ) + + machine.succeed("incus storage create zfs_pool zfs source=zfs_pool/incus") + machine.succeed("zfs list zfs_pool/incus") + + machine.succeed("incus storage volume create zfs_pool test_fs --type filesystem") + machine.succeed("incus storage volume create zfs_pool test_vol --type block") + + machine.succeed("incus storage show zfs_pool") + machine.succeed("incus storage volume list zfs_pool") + machine.succeed("incus storage volume show zfs_pool test_fs") + machine.succeed("incus storage volume show zfs_pool test_vol") + + machine.succeed("incus create zfs1 --empty --storage zfs_pool") + machine.succeed("incus list zfs1") + '' + + + + lib.optionalString storageLvm # python + '' + with subtest("Verify lvm pool created and usable"): + machine.succeed("incus storage create lvm_pool lvm source=/dev/vdc lvm.vg_name=incus_pool") + machine.succeed("vgs incus_pool") + + machine.succeed("incus storage volume create lvm_pool test_fs --type filesystem") + machine.succeed("incus storage volume create lvm_pool test_vol --type block") + + machine.succeed("incus storage show lvm_pool") + + machine.succeed("incus storage volume list lvm_pool") + machine.succeed("incus storage volume show lvm_pool test_fs") + machine.succeed("incus storage volume show lvm_pool test_vol") + + machine.succeed("incus create lvm1 --empty --storage zfs_pool") + machine.succeed("incus list lvm1") + ''; + } +) diff --git a/nixos/tests/incus/incusd-options.nix b/nixos/tests/incus/incusd-options.nix deleted file mode 100644 index 494abd1549d3..000000000000 --- a/nixos/tests/incus/incusd-options.nix +++ /dev/null @@ -1,140 +0,0 @@ -# this is a set of tests for non-default options. typically the default options -# will be handled by the other tests -import ../make-test-python.nix ( - { - pkgs, - lib, - incus ? pkgs.incus-lts, - ... - }: - - let - releases = import ../../release.nix { - configuration = { - # Building documentation makes the test unnecessarily take a longer time: - documentation.enable = lib.mkForce false; - }; - }; - - container-image-metadata = "${ - releases.incusContainerMeta.${pkgs.stdenv.hostPlatform.system} - }/tarball/nixos-image-lxc-*-${pkgs.stdenv.hostPlatform.system}.tar.xz"; - container-image-rootfs = "${ - releases.incusContainerImage.${pkgs.stdenv.hostPlatform.system} - }/nixos-lxc-image-${pkgs.stdenv.hostPlatform.system}.squashfs"; - in - { - name = "incusd-options"; - - meta = { - maintainers = lib.teams.lxc.members; - }; - - nodes.machine = { - virtualisation = { - cores = 2; - memorySize = 1024; - diskSize = 4096; - - incus = { - enable = true; - package = incus; - softDaemonRestart = false; - - preseed = { - networks = [ - { - name = "incusbr0"; - type = "bridge"; - config = { - "ipv4.address" = "10.0.100.1/24"; - "ipv4.nat" = "true"; - }; - } - ]; - profiles = [ - { - name = "default"; - devices = { - eth0 = { - name = "eth0"; - network = "incusbr0"; - type = "nic"; - }; - root = { - path = "/"; - pool = "default"; - size = "35GiB"; - type = "disk"; - }; - }; - } - ]; - storage_pools = [ - { - name = "default"; - driver = "dir"; - } - ]; - }; - }; - - }; - - networking.nftables.enable = true; - - users.users.testuser = { - isNormalUser = true; - shell = pkgs.bashInteractive; - group = "incus"; - uid = 1000; - }; - }; - - testScript = # python - '' - def wait_for_instance(name: str, project: str = "default"): - def instance_is_up(_) -> bool: - status, _ = machine.execute(f"incus exec {name} --disable-stdin --force-interactive --project {project} -- /run/current-system/sw/bin/systemctl is-system-running") - return status == 0 - - with machine.nested(f"Waiting for instance {name} to start and be usable"): - retry(instance_is_up) - - machine.wait_for_unit("incus.service") - machine.wait_for_unit("incus-preseed.service") - - with subtest("Container image can be imported"): - machine.succeed("incus image import ${container-image-metadata} ${container-image-rootfs} --alias nixos") - - with subtest("Container can be launched and managed"): - machine.succeed("incus launch nixos instance1") - wait_for_instance("instance1") - machine.succeed("echo true | incus exec instance1 /run/current-system/sw/bin/bash -") - - with subtest("Verify preseed resources created"): - machine.succeed("incus profile show default") - machine.succeed("incus network info incusbr0") - machine.succeed("incus storage show default") - - with subtest("Instance is stopped when softDaemonRestart is disabled and services is stopped"): - pid = machine.succeed("incus info instance1 | grep 'PID'").split(":")[1].strip() - machine.succeed(f"ps {pid}") - machine.succeed("systemctl stop incus") - machine.fail(f"ps {pid}") - - with subtest("incus-user allows restricted access for users"): - machine.fail("incus project show user-1000") - machine.succeed("su - testuser bash -c 'incus list'") - # a project is created dynamically for the user - machine.succeed("incus project show user-1000") - # users shouldn't be able to list storage pools - machine.fail("su - testuser bash -c 'incus storage list'") - - with subtest("incus-user allows users to launch instances"): - machine.succeed("su - testuser bash -c 'incus image import ${container-image-metadata} ${container-image-rootfs} --alias nixos'") - machine.succeed("su - testuser bash -c 'incus launch nixos instance2'") - wait_for_instance("instance2", "user-1000") - ''; - } -) diff --git a/nixos/tests/incus/openvswitch.nix b/nixos/tests/incus/openvswitch.nix deleted file mode 100644 index a825313fad7e..000000000000 --- a/nixos/tests/incus/openvswitch.nix +++ /dev/null @@ -1,78 +0,0 @@ -import ../make-test-python.nix ( - { - pkgs, - lib, - incus ? pkgs.incus-lts, - ... - }: - - { - name = "incus-openvswitch"; - - meta = { - maintainers = lib.teams.lxc.members; - }; - - nodes.machine = - { lib, ... }: - { - virtualisation = { - incus = { - enable = true; - package = incus; - }; - - vswitch.enable = true; - incus.preseed = { - networks = [ - { - name = "nixostestbr0"; - type = "bridge"; - config = { - "bridge.driver" = "openvswitch"; - "ipv4.address" = "10.0.100.1/24"; - "ipv4.nat" = "true"; - }; - } - ]; - profiles = [ - { - name = "nixostest_default"; - devices = { - eth0 = { - name = "eth0"; - network = "nixostestbr0"; - type = "nic"; - }; - root = { - path = "/"; - pool = "default"; - size = "35GiB"; - type = "disk"; - }; - }; - } - ]; - storage_pools = [ - { - name = "nixostest_pool"; - driver = "dir"; - } - ]; - }; - }; - networking.nftables.enable = true; - }; - - testScript = '' - machine.wait_for_unit("incus.service") - machine.wait_for_unit("incus-preseed.service") - - with subtest("Verify openvswitch bridge"): - machine.succeed("incus network info nixostestbr0") - - with subtest("Verify openvswitch bridge"): - machine.succeed("ovs-vsctl br-exists nixostestbr0") - ''; - } -) diff --git a/nixos/tests/incus/socket-activated.nix b/nixos/tests/incus/socket-activated.nix deleted file mode 100644 index 3223591ebfe7..000000000000 --- a/nixos/tests/incus/socket-activated.nix +++ /dev/null @@ -1,41 +0,0 @@ -import ../make-test-python.nix ( - { - pkgs, - lib, - incus ? pkgs.incus-lts, - ... - }: - - { - name = "incus-socket-activated"; - - meta = { - maintainers = lib.teams.lxc.members; - }; - - nodes.machine = - { lib, ... }: - { - virtualisation = { - incus = { - enable = true; - package = incus; - socketActivation = true; - }; - }; - networking.nftables.enable = true; - }; - - testScript = '' - machine.wait_for_unit("incus.socket") - - # ensure service is not running by default - machine.fail("systemctl is-active incus.service") - machine.fail("systemctl is-active incus-preseed.service") - - # access the socket and ensure the service starts - machine.succeed("incus list") - machine.wait_for_unit("incus.service") - ''; - } -) diff --git a/nixos/tests/incus/storage.nix b/nixos/tests/incus/storage.nix deleted file mode 100644 index 2ca5dfcd0624..000000000000 --- a/nixos/tests/incus/storage.nix +++ /dev/null @@ -1,84 +0,0 @@ -import ../make-test-python.nix ( - { - pkgs, - lib, - incus ? pkgs.incus-lts, - ... - }: - - { - name = "incus-storage"; - - meta = { - maintainers = lib.teams.lxc.members; - }; - - nodes.machine = { - boot.supportedFilesystems = [ "zfs" ]; - boot.zfs.forceImportRoot = false; - - environment.systemPackages = [ pkgs.parted ]; - - networking.hostId = "01234567"; - networking.nftables.enable = true; - - services.lvm = { - boot.thin.enable = true; - dmeventd.enable = true; - }; - - virtualisation = { - emptyDiskImages = [ - 2048 - 2048 - ]; - incus = { - enable = true; - package = incus; - }; - }; - }; - - testScript = # python - '' - machine.wait_for_unit("incus.service") - - with subtest("Verify zfs pool created and usable"): - machine.succeed( - "zpool status", - "parted --script /dev/vdb mklabel gpt", - "zpool create zfs_pool /dev/vdb", - ) - - machine.succeed("incus storage create zfs_pool zfs source=zfs_pool/incus") - machine.succeed("zfs list zfs_pool/incus") - - machine.succeed("incus storage volume create zfs_pool test_fs --type filesystem") - machine.succeed("incus storage volume create zfs_pool test_vol --type block") - - machine.succeed("incus storage show zfs_pool") - machine.succeed("incus storage volume list zfs_pool") - machine.succeed("incus storage volume show zfs_pool test_fs") - machine.succeed("incus storage volume show zfs_pool test_vol") - - machine.succeed("incus create zfs1 --empty --storage zfs_pool") - machine.succeed("incus list zfs1") - - with subtest("Verify lvm pool created and usable"): - machine.succeed("incus storage create lvm_pool lvm source=/dev/vdc lvm.vg_name=incus_pool") - machine.succeed("vgs incus_pool") - - machine.succeed("incus storage volume create lvm_pool test_fs --type filesystem") - machine.succeed("incus storage volume create lvm_pool test_vol --type block") - - machine.succeed("incus storage show lvm_pool") - - machine.succeed("incus storage volume list lvm_pool") - machine.succeed("incus storage volume show lvm_pool test_fs") - machine.succeed("incus storage volume show lvm_pool test_vol") - - machine.succeed("incus create lvm1 --empty --storage zfs_pool") - machine.succeed("incus list lvm1") - ''; - } -) diff --git a/nixos/tests/incus/virtual-machine.nix b/nixos/tests/incus/virtual-machine.nix deleted file mode 100644 index ba1150e5a79f..000000000000 --- a/nixos/tests/incus/virtual-machine.nix +++ /dev/null @@ -1,95 +0,0 @@ -import ../make-test-python.nix ( - { - pkgs, - lib, - incus ? pkgs.incus-lts, - ... - }: - - let - releases = import ../../release.nix { - configuration = { - # Building documentation makes the test unnecessarily take a longer time: - documentation.enable = lib.mkForce false; - - # Our tests require `grep` & friends: - environment.systemPackages = with pkgs; [ busybox ]; - }; - }; - - vm-image-metadata = releases.incusVirtualMachineImageMeta.${pkgs.stdenv.hostPlatform.system}; - vm-image-disk = releases.incusVirtualMachineImage.${pkgs.stdenv.hostPlatform.system}; - - instance-name = "instance1"; - in - { - name = "incus-virtual-machine"; - - meta = { - maintainers = lib.teams.lxc.members; - }; - - nodes.machine = - { ... }: - { - virtualisation = { - # Ensure test VM has enough resources for creating and managing guests - cores = 2; - memorySize = 1024; - diskSize = 4096; - - incus = { - enable = true; - package = incus; - }; - }; - networking.nftables.enable = true; - }; - - testScript = # python - '' - def instance_is_up(_) -> bool: - status, _ = machine.execute("incus exec ${instance-name} --disable-stdin --force-interactive /run/current-system/sw/bin/systemctl -- is-system-running") - return status == 0 - - machine.wait_for_unit("incus.service") - - machine.succeed("incus admin init --minimal") - - with subtest("virtual-machine image can be imported"): - machine.succeed("incus image import ${vm-image-metadata}/*/*.tar.xz ${vm-image-disk}/nixos.qcow2 --alias nixos") - - with subtest("virtual-machine can be created"): - machine.succeed("incus create nixos ${instance-name} --vm --config limits.memory=512MB --config security.secureboot=false") - - with subtest("virtual tpm can be configured"): - machine.succeed("incus config device add ${instance-name} vtpm tpm path=/dev/tpm0") - - with subtest("virtual-machine can be launched and become available"): - machine.succeed("incus start ${instance-name}") - with machine.nested("Waiting for instance to start and be usable"): - retry(instance_is_up) - - with subtest("incus-agent is started"): - machine.succeed("incus exec ${instance-name} systemctl is-active incus-agent") - - with subtest("incus-agent has a valid path"): - machine.succeed("incus exec ${instance-name} -- bash -c 'true'") - - with subtest("guest supports cpu hotplug"): - machine.succeed("incus config set ${instance-name} limits.cpu=1") - count = int(machine.succeed("incus exec ${instance-name} -- nproc").strip()) - assert count == 1, f"Wrong number of CPUs reported, want: 1, got: {count}" - - machine.succeed("incus config set ${instance-name} limits.cpu=2") - count = int(machine.succeed("incus exec ${instance-name} -- nproc").strip()) - assert count == 2, f"Wrong number of CPUs reported, want: 2, got: {count}" - - with subtest("Instance remains running when softDaemonRestart is enabled and services is stopped"): - pid = machine.succeed("incus info ${instance-name} | grep 'PID'").split(":")[1].strip() - machine.succeed(f"ps {pid}") - machine.succeed("systemctl stop incus") - machine.succeed(f"ps {pid}") - ''; - } -) diff --git a/pkgs/by-name/di/distrobuilder/package.nix b/pkgs/by-name/di/distrobuilder/package.nix index ec4253d6b450..bc204e8d74a6 100644 --- a/pkgs/by-name/di/distrobuilder/package.nix +++ b/pkgs/by-name/di/distrobuilder/package.nix @@ -63,8 +63,7 @@ buildGoModule rec { passthru = { tests = { - incus-legacy-init = nixosTests.incus.container-legacy-init; - incus-systemd-init = nixosTests.incus.container-systemd-init; + incus-lts = nixosTests.incus-lts.container; }; generator = callPackage ./generator.nix { inherit src version; }; diff --git a/pkgs/by-name/in/incus/generic.nix b/pkgs/by-name/in/incus/generic.nix index 7e2483f1b2d2..fda8a541bc25 100644 --- a/pkgs/by-name/in/incus/generic.nix +++ b/pkgs/by-name/in/incus/generic.nix @@ -124,7 +124,7 @@ buildGoModule rec { ; }; - tests = if lts then nixosTests.incus-lts else nixosTests.incus; + tests = if lts then nixosTests.incus-lts.all else nixosTests.incus.all; ui = callPackage ./ui.nix { }; diff --git a/pkgs/by-name/lx/lxc/package.nix b/pkgs/by-name/lx/lxc/package.nix index 3f00ccb82b52..37bb518c76cd 100644 --- a/pkgs/by-name/lx/lxc/package.nix +++ b/pkgs/by-name/lx/lxc/package.nix @@ -85,8 +85,7 @@ stdenv.mkDerivation (finalAttrs: { passthru = { tests = { - incus-legacy-init = nixosTests.incus.container-legacy-init; - incus-systemd-init = nixosTests.incus.container-systemd-init; + incus-lts = nixosTests.incus-lts.container; lxc = nixosTests.lxc; lxd = nixosTests.lxd.container; }; diff --git a/pkgs/by-name/lx/lxcfs/package.nix b/pkgs/by-name/lx/lxcfs/package.nix index 5082bc395136..31008cc96a4a 100644 --- a/pkgs/by-name/lx/lxcfs/package.nix +++ b/pkgs/by-name/lx/lxcfs/package.nix @@ -68,8 +68,7 @@ stdenv.mkDerivation rec { passthru = { tests = { - incus-container-legacy-init = nixosTests.incus.container-legacy-init; - incus-container-systemd-init = nixosTests.incus.container-systemd-init; + incus-lts = nixosTests.incus-lts.container; }; updateScript = nix-update-script { };