vendor: drop the hardcoded /etc/network mount for SKIP_INIT containers

Override _mount_binds in VendorDockerVM: for GNS3_SKIP_INIT containers the
/etc/network volume (GNS3's own network config consumed by init.sh's ifup)
is dead weight — init.sh never runs and the NOS manages its own
interfaces. The override removes the bind, filters /etc/network out of
self._volumes (keeping GNS3_VOLUMES and the bridge/fix passes consistent)
and deletes the host-side skeleton directory created by the base class.
Without GNS3_SKIP_INIT the mount is kept, matching base behaviour.
_persistent_volumes() is removed — the mount override is now the single
filter point.
This commit is contained in:
YueGuobin 2026-08-12 23:41:45 +08:00
parent 46e863b975
commit f5554d816a
No known key found for this signature in database
2 changed files with 32 additions and 21 deletions

View File

@ -241,12 +241,14 @@ host ──Docker bind mount──▶ /gns3volumes/etc/opt/srlinux (always m
> host-side root-owned, and an unprivileged GNS3 process cannot chown them
> from the host. Container-side root (with GNS3's `UsernsMode: host`) can.
With `GNS3_SKIP_INIT`, `/etc/network` is skipped by both vendor passes
(`VendorDockerVM._persistent_volumes()`): it holds GNS3's own network config
for init.sh's `ifup`, which never runs for SKIP_INIT containers — the NOS
manages its own interfaces. The Docker mount itself is left alone (shared
`_mount_binds`, hardcoded at `docker_vm.py` `_mount_binds()`); only the
vendor-side bridge/fix passes skip it.
With `GNS3_SKIP_INIT`, GNS3's hardcoded `/etc/network` volume (see
`docker_vm.py` `_mount_binds()`) is dropped entirely by
`VendorDockerVM._mount_binds()`: it holds GNS3's own network config for
init.sh's `ifup`, which never runs for SKIP_INIT containers — the NOS
manages its own interfaces. The override removes the bind, filters the
volume out of `self._volumes`, and deletes the host-side skeleton directory
the base class just created. Without `GNS3_SKIP_INIT` the mount is kept
(behaviour matches the base class).
### Lifecycle summary

View File

@ -27,9 +27,11 @@ container behaves identically to DockerVM.
"""
import asyncio
import contextlib
import json
import logging
import os
import shutil
from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer
from gns3server.compute.docker.docker_vm import DockerVM
@ -79,6 +81,26 @@ class VendorDockerVM(DockerVM):
# ---- hook overrides ---------------------------------------------------
def _mount_binds(self, image_info):
"""
Override: for SKIP_INIT containers, drop GNS3's hardcoded
/etc/network volume. It holds GNS3's own network config consumed by
init.sh's `ifup`; init.sh never runs for SKIP_INIT containers (the
NOS manages its own interfaces), so the mount would be dead weight.
Removes the bind, drops the volume from self._volumes (so
GNS3_VOLUMES and the vendor passes stay consistent) and deletes the
host-side skeleton directory the base class just created.
"""
binds = super()._mount_binds(image_info)
if self._gns3_init:
return binds
binds = [b for b in binds if b.get("Target") != "/gns3volumes/etc/network"]
self._volumes = [v for v in self._volumes if v != "/etc/network"]
shutil.rmtree(os.path.join(self.working_dir, "etc", "network"), ignore_errors=True)
with contextlib.suppress(OSError):
os.rmdir(os.path.join(self.working_dir, "etc"))
return binds
def _prepare_init_and_interface_env(self, params):
"""
Override: conditionally prepend init.sh, and honour
@ -95,19 +117,6 @@ class VendorDockerVM(DockerVM):
last_ifname = f"eth{self.adapters - 1}"
params["Env"].append(f"GNS3_MAX_ETHERNET={last_ifname}")
def _persistent_volumes(self):
"""
Volumes relevant to vendor persistence. With GNS3_SKIP_INIT, drop
/etc/network GNS3's own network config for init.sh's ifup, unused
when init.sh is skipped (the NOS manages its own interfaces). The
Docker mount itself is left alone (shared _mount_binds); only the
vendor-side bridge/fix passes skip it. Without SKIP_INIT the full
list is returned so behaviour matches the base class.
"""
if self._gns3_init:
return self._volumes
return [v for v in self._volumes if v != "/etc/network"]
def _get_container_ifname(self, adapter_number):
"""
Override: honour GNS3_INTERFACE_NAMES (e.g. mgmt0, e1-1) in adapter
@ -170,7 +179,7 @@ class VendorDockerVM(DockerVM):
return
uid, gid = os.getuid(), os.getgid()
for volume in self._persistent_volumes():
for volume in self._volumes:
target = f"/gns3volumes{volume}"
log.debug("Docker container '%s' fix ownership on %s", self._name, target)
try:
@ -212,7 +221,7 @@ class VendorDockerVM(DockerVM):
Permission-changes recorded by _fix_permissions at the previous
stop are restored (best-effort).
"""
for volume in self._persistent_volumes():
for volume in self._volumes:
vol_target = f"/gns3volumes{volume}"
# fmt: off
script = (