mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 05:51:15 +02:00
docker: mask systemd-udevd in privileged containers (GNS3_MASK_UDEV)
A privileged systemd-based NOS container (Cisco XRd boots /usr/sbin/init)
runs systemd-udevd, which on startup coldplugs every device it can reach.
In privileged mode that includes the HOST's USB/input/audio/disk devices,
so every XRd start reconnects USB, mutes audio, and disrupts the host
journal -- highly disruptive on Linux desktops (caught in the act: the
container's udevd was even rescanning the host BTRFS root device).
XRd doesn't need udev (its interfaces are pre-created by GNS3 veth and
mapped via XR_INTERFACES). Add two opt-in env vars, consumed host-side at
container create time in the inherited DockerVM.create (so VendorDockerVM
nodes get it too):
GNS3_MASK_UDEV=1 -> bind /dev/null over the udevd unit, its two
activation sockets, and the coldplug/settle
trigger services
GNS3_MASK_SYSTEMD=u1,u2 -> bind /dev/null over arbitrary units in
/etc/systemd/system/ (comma/semicolon list)
Only injected when set, so ordinary nodes are unaffected.
This commit is contained in:
2 files changed
+61
No files matched your search
@@ -308,6 +308,29 @@ async def test_create_applies_env_host_config(compute_project, manager):
|
||||
), "GNS3_ user vars must not leak into the container environment"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_masks_systemd_units(compute_project, manager):
|
||||
"""
|
||||
GNS3_MASK_UDEV=1 binds /dev/null over the udev units, and GNS3_MASK_SYSTEMD
|
||||
does the same for arbitrary units -- stopping a privileged systemd container
|
||||
from udev-coldplugging host devices.
|
||||
"""
|
||||
|
||||
environment = "GNS3_MASK_UDEV=1\nGNS3_MASK_SYSTEMD=foo.service,bar.socket"
|
||||
response = {"Id": "e90e34656806", "Warnings": []}
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "ubuntu"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
|
||||
vm = DockerVM("test", str(uuid.uuid4()), compute_project, manager, "ubuntu", environment=environment)
|
||||
await vm.create()
|
||||
masked = {m["Target"] for m in mock.call_args[1]["data"]["HostConfig"]["Mounts"]
|
||||
if m.get("Source") == "/dev/null"}
|
||||
for unit in DockerVM._UDEV_UNITS:
|
||||
assert f"/etc/systemd/system/{unit}" in masked
|
||||
assert "/etc/systemd/system/foo.service" in masked
|
||||
assert "/etc/systemd/system/bar.socket" in masked
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_with_extra_configs(compute_project, manager):
|
||||
"""
|
||||
|
||||
Reference in new issue
Block a user