incus: fix instance unclean shutdown, add per-instance lxcfs support (#373920)

This commit is contained in:
Adam C. Stephens
2025-01-25 10:05:03 -05:00
committed by GitHub
2 changed files with 70 additions and 30 deletions
+3
View File
@@ -38,6 +38,7 @@ let
libnvidia-container
libxfs
lvm2
lxcfs
minio
minio-client
nftables
@@ -121,6 +122,7 @@ let
environment = lib.mkMerge [
{
INCUS_EDK2_PATH = ovmf;
INCUS_LXC_HOOK = "${cfg.lxcPackage}/share/lxc/hooks";
INCUS_LXC_TEMPLATE_CONFIG = "${pkgs.lxcfs}/share/lxc/config";
INCUS_USBIDS_PATH = "${pkgs.hwdata}/share/hwdata/usb.ids";
PATH = lib.mkForce serverBinPath;
@@ -401,6 +403,7 @@ in
"incus.socket"
];
requires = [ "incus.socket" ];
wantedBy = config.systemd.services.incus.wantedBy;
serviceConfig = {
ExecStart = "${incus-startup} start";
+67 -30
View File
@@ -190,7 +190,7 @@ import ../make-test-python.nix (
def cleanup():
# avoid conflict between preseed and cleanup operations
machine.wait_for_unit("incus-preseed.service")
machine.execute("systemctl kill incus-preseed.service")
instances = json.loads(machine.succeed("incus list --format json --all-projects"))
with subtest("Stopping all running instances"):
@@ -228,39 +228,41 @@ import ../make-test-python.nix (
alias = "nixos/container/${variant}"
variant = "${variant}"
with subtest("Container image can be imported"):
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"):
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"):
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("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("virtual tpm can be configured"):
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("container software 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")
@@ -268,7 +270,7 @@ import ../make-test-python.nix (
machine.fail(f"incus exec container-{variant}1 -- test -e /dev/tpm0")
with subtest("lxc-generator"):
with subtest("container lxc-generator compatibility"):
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")
@@ -293,14 +295,36 @@ import ../make-test-python.nix (
check_sysctl(f"container-{variant}2")
with subtest("container supports per-instance lxcfs"):
machine.succeed(f"incus stop container-{variant}1")
machine.fail(f"pgrep -a lxcfs | grep 'incus/devices/container-{variant}1/lxcfs'")
with subtest("Instance remains running when softDaemonRestart is enabled and service is stopped"):
machine.succeed("incus config set instances.lxcfs.per_instance=true")
machine.succeed(f"incus start container-{variant}1")
wait_for_instance(f"container-{variant}1")
machine.succeed(f"pgrep -a lxcfs | grep 'incus/devices/container-{variant}1/lxcfs'")
with subtest("container can successfully restart"):
machine.succeed(f"incus restart container-{variant}1")
wait_for_instance(f"container-{variant}1")
with subtest("container 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")
with subtest("containers stop with incus-startup.service"):
pid = machine.succeed(f"incus info container-{variant}1 | grep 'PID'").split(":")[1].strip()
machine.succeed(f"ps {pid}")
machine.succeed("systemctl stop incus-startup.service")
machine.wait_until_fails(f"ps {pid}", timeout=120)
machine.succeed("systemctl start incus-startup.service")
cleanup()
''
@@ -325,7 +349,7 @@ import ../make-test-python.nix (
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"):
with subtest("virtual-machine software tpm can be configured"):
machine.succeed(f"incus config device add vm-{variant}1 vtpm tpm path=/dev/tpm0")
@@ -334,25 +358,30 @@ import ../make-test-python.nix (
wait_for_instance(f"vm-{variant}1")
with subtest("incus-agent is started"):
with subtest("virtual-machine 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"):
with subtest("virtual-machine 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"):
with subtest("virtual-machine 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"):
with subtest("virtual-machine 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"):
with subtest("virtual-machine can successfully restart"):
machine.succeed(f"incus restart vm-{variant}1")
wait_for_instance(f"vm-{variant}1")
with subtest("virtual-machine 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")
@@ -360,13 +389,21 @@ import ../make-test-python.nix (
machine.succeed("systemctl start incus")
with subtest("virtual-machines stop with incus-startup.service"):
pid = machine.succeed(f"incus info vm-{variant}1 | grep 'PID'").split(":")[1].strip()
machine.succeed(f"ps {pid}")
machine.succeed("systemctl stop incus-startup.service")
machine.wait_until_fails(f"ps {pid}", timeout=120)
machine.succeed("systemctl start incus-startup.service")
cleanup()
''
) "" initVariants)
+
# python
''
with subtest("Can launch CSM virtual machine"):
with subtest("virtual-machine can launch CSM (BIOS)"):
machine.succeed("incus init csm --vm --empty -c security.csm=true -c security.secureboot=false")
machine.succeed("incus start csm")