From 5ef48168f425b8211ac8a7fb2d2d395bfe347363 Mon Sep 17 00:00:00 2001 From: Autumn Liu Date: Fri, 11 Sep 2026 15:50:58 -0500 Subject: [PATCH] fix bug --- dsl.nix | 15 ++++++++------- tests/server-n0/integration.py | 5 +++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/dsl.nix b/dsl.nix index 8edf4a9..0d87553 100644 --- a/dsl.nix +++ b/dsl.nix @@ -222,11 +222,13 @@ rec { : Bind mounts, keyed by mount point. `resources.devices` - : Host device nodes to expose, as paths. Bound into the container's `/dev` - and added to the unit's `DeviceAllow=` - the bind alone leaves the cgroup - denying `open()`. Nodes keep their host ownership, so a consumer inside - needs `isolation.privateUsers = "identity"` for the owning gid to mean - anything. + : Host device nodes to expose, as paths, added to the unit's + `DeviceAllow=`. nspawn populates a handful of privileged devices + (`/dev/kvm`, `/dev/net/tun`, ...) into the container's own `/dev` once + the cgroup allows it, and silently skips ones the host doesn't have - + no `resources.fs` bind mount needed. Nodes keep their host ownership, + so a consumer inside needs `isolation.privateUsers = "identity"` for + the owning gid to mean anything. `isolation.nixDaemon` : Whether the Nix daemon and CLI are available inside the container. @@ -293,7 +295,6 @@ rec { + lib.optionalString useIdmap ":idmap" ) allBindMounts; bindMountHostPaths = map (bm: bm.hostPath) (lib.attrValues allBindMounts); - deviceFlags = map (d: "--bind=${d}") devices; inherit (deriveIdentity ifPrefix.nspawn name) iface mac @@ -380,7 +381,7 @@ rec { nixosContainer = { inherit autoStart privateUsers; bindMounts = { }; - extraFlags = bindMountExtraFlags ++ deviceFlags; + extraFlags = bindMountExtraFlags; privateNetwork = true; extraVeths = linkVeths; config = diff --git a/tests/server-n0/integration.py b/tests/server-n0/integration.py index 10bc9a5..c454664 100644 --- a/tests/server-n0/integration.py +++ b/tests/server-n0/integration.py @@ -338,6 +338,11 @@ with subtest("(functional): published ports follow the container's lifetime"): with subtest("(functional): declared devices are usable in-container"): for name, devices in DEVICES.items(): for dev in devices: + if server.execute(f"test -e {dev}")[0] != 0: + # host lacks the device (e.g. /dev/kvm without nested + # virtualization, as in this test's own VM) - nspawn skips + # populating it in-container, so there's nothing to check. + continue # opened, not stat'd: without DeviceAllow= the node is still visible server.succeed(ct_cmd(name, f"exec 3<> {dev}"))