refactor: ruff autofixes

This commit is contained in:
Mark Paronyan committed 2026-09-27 15:55:10 +03:00
1 parent 2ac637c662
commit a0450b6bce
455 files changed
+12322 -14762

No files matched your search

+120 -91
View File
@@ -236,7 +236,9 @@ class DockerVM(BaseNode):
"""
if not is_rfc1123_hostname_valid(new_name):
raise DockerError(f"'{new_name}' is an invalid name to rename Docker container '{self._name}'. Allowed characters: letters (a-z, A-Z), digits (0-9), and hyphens (-). The name cannot start or end with a hyphen.")
raise DockerError(
f"'{new_name}' is an invalid name to rename Docker container '{self._name}'. Allowed characters: letters (a-z, A-Z), digits (0-9), and hyphens (-). The name cannot start or end with a hyphen."
)
super(DockerVM, DockerVM).name.__set__(self, new_name)
@property
@@ -275,10 +277,10 @@ class DockerVM(BaseNode):
else:
self._mac_address = mac_address
log.debug('Docker container "{name}" [{id}]: MAC address changed to {mac_addr}'.format(
name=self._name,
id=self._id,
mac_addr=self._mac_address)
log.debug(
'Docker container "{name}" [{id}]: MAC address changed to {mac_addr}'.format(
name=self._name, id=self._id, mac_addr=self._mac_address
)
)
@property
@@ -453,12 +455,7 @@ class DockerVM(BaseNode):
raise DockerError(f"Cannot access resources: {e}")
log.debug(f'Mount resources from "{resources_path}"')
binds = [{
"Type": "bind",
"Source": resources_path,
"Target": "/gns3",
"ReadOnly": True
}]
binds = [{"Type": "bind", "Source": resources_path, "Target": "/gns3", "ReadOnly": True}]
self._image_id = image_info.get("Id") or self._image_id
# We mount our own etc/network
@@ -471,11 +468,7 @@ class DockerVM(BaseNode):
for volume in self._volumes:
source = os.path.join(self.working_dir, os.path.relpath(volume, "/"))
os.makedirs(source, exist_ok=True)
binds.append({
"Type": "bind",
"Source": source,
"Target": "/gns3volumes{}".format(volume)
})
binds.append({"Type": "bind", "Source": source, "Target": "/gns3volumes{}".format(volume)})
# Inject extra config files: write each to the node working directory and
# bind-mount it read-only at its target path. Single-file binds are applied
@@ -485,9 +478,7 @@ class DockerVM(BaseNode):
target = cfg["target"] if isinstance(cfg, dict) else cfg.target
content = cfg["content"] if isinstance(cfg, dict) else cfg.content
if not target.startswith("/") or target.endswith("/") or ".." in target.split("/"):
raise DockerError(
f"Extra config target '{target}' must be an absolute file path and not contain '..'."
)
raise DockerError(f"Extra config target '{target}' must be an absolute file path and not contain '..'.")
for volume in self._volumes:
# A single-file bind gets covered by the volume's bind mount at
# start (init.sh or the vendor volume bridge), so the injected
@@ -497,18 +488,22 @@ class DockerVM(BaseNode):
log.warning(
"Extra config target '%s' on container '%s' is shadowed by persisted volume '%s' "
"and will not take effect; pick a target outside persisted volumes.",
target, self._name, volume,
target,
self._name,
volume,
)
host_path = os.path.join(self.working_dir, "configs", target.lstrip("/"))
os.makedirs(os.path.dirname(host_path), exist_ok=True)
with open(host_path, "w") as f:
f.write(content)
binds.append({
"Type": "bind",
"Source": host_path,
"Target": target,
"ReadOnly": True,
})
binds.append(
{
"Type": "bind",
"Source": host_path,
"Target": target,
"ReadOnly": True,
}
)
return binds
@@ -554,7 +549,8 @@ class DockerVM(BaseNode):
#auto eth{adapter}
#iface eth{adapter} inet dhcp
#\thostname {hostname}
""".format(adapter=adapter, hostname=self._name))
""".format(adapter=adapter, hostname=self._name)
)
return path
def _prepare_init_and_interface_env(self, params):
@@ -573,9 +569,11 @@ class DockerVM(BaseNode):
"""
if ":" in os.path.splitdrive(self.working_dir)[1]:
raise DockerError("Cannot create a Docker container with a project directory containing a colon character (':')")
raise DockerError(
"Cannot create a Docker container with a project directory containing a colon character (':')"
)
#await self.manager.install_resources()
# await self.manager.install_resources()
try:
image_infos = await self._get_image_information()
@@ -601,8 +599,7 @@ class DockerVM(BaseNode):
available_cpus = psutil.cpu_count(logical=True)
if self._cpus > available_cpus:
raise DockerError(
f"You have allocated too many CPUs for the Docker container "
f"(max available is {available_cpus} CPUs)"
f"You have allocated too many CPUs for the Docker container (max available is {available_cpus} CPUs)"
)
# Prepare persistent volume content before the container and its
@@ -622,7 +619,7 @@ class DockerVM(BaseNode):
"Mounts": self._mount_binds(image_infos),
"Memory": self._memory * (1024 * 1024), # convert memory to bytes
"NanoCpus": int(self._cpus * 1e9), # convert cpus to nano cpus
"UsernsMode": "host"
"UsernsMode": "host",
},
"Volumes": {},
"Env": ["container=docker"], # Systemd compliant: https://github.com/GNS3/gns3-server/issues/573
@@ -651,8 +648,11 @@ class DockerVM(BaseNode):
devices = self._format_devices(line.split("=", 1)[1])
if devices:
params["HostConfig"]["Devices"] = devices
elif line.startswith("GNS3_MASK_UDEV=") and \
line.split("=", 1)[1].strip().lower() in ("1", "true", "yes"):
elif line.startswith("GNS3_MASK_UDEV=") and line.split("=", 1)[1].strip().lower() in (
"1",
"true",
"yes",
):
# A privileged systemd-based NOS container (e.g. Cisco XRd)
# runs systemd-udevd, which coldplugs every device it can see
# -- and in privileged mode that includes the HOST's USB/input/
@@ -660,24 +660,28 @@ class DockerVM(BaseNode):
# XRd doesn't need udev (interfaces are pre-created by GNS3), so
# bind /dev/null over the udev units to keep it from running.
for target in [f"/etc/systemd/system/{u}" for u in self._UDEV_UNITS] + list(self._UDEVADM_PATHS):
params["HostConfig"]["Mounts"].append({
"Type": "bind",
"Source": "/dev/null",
"Target": target,
"ReadOnly": True,
})
params["HostConfig"]["Mounts"].append(
{
"Type": "bind",
"Source": "/dev/null",
"Target": target,
"ReadOnly": True,
}
)
elif line.startswith("GNS3_MASK_SYSTEMD="):
# Generic form: comma/semicolon-separated unit names to mask
# the same way (bind /dev/null over /etc/systemd/system/<unit>).
for unit in line.split("=", 1)[1].replace(";", ",").split(","):
unit = unit.strip()
if unit and "/" not in unit and ".." not in unit:
params["HostConfig"]["Mounts"].append({
"Type": "bind",
"Source": "/dev/null",
"Target": f"/etc/systemd/system/{unit}",
"ReadOnly": True,
})
params["HostConfig"]["Mounts"].append(
{
"Type": "bind",
"Source": "/dev/null",
"Target": f"/etc/systemd/system/{unit}",
"ReadOnly": True,
}
)
# Overlapping bind targets (GNS3_MASK_UDEV together with a
# GNS3_MASK_SYSTEMD entry for the same unit, an extra_configs target
@@ -754,12 +758,14 @@ class DockerVM(BaseNode):
"QT_GRAPHICSSYSTEM=native"
) # To fix a Qt issue: https://github.com/GNS3/gns3-server/issues/556
params["Env"].append(f"DISPLAY=:{self._display}")
params["HostConfig"]["Mounts"].append({
"Type": "bind",
"Source": f"/tmp/.X11-unix/X{self._display}",
"Target": f"/tmp/.X11-unix/X{self._display}",
"ReadOnly": True
})
params["HostConfig"]["Mounts"].append(
{
"Type": "bind",
"Source": f"/tmp/.X11-unix/X{self._display}",
"Target": f"/tmp/.X11-unix/X{self._display}",
"ReadOnly": True,
}
)
if self._extra_hosts:
extra_hosts = self._format_extra_hosts(self._extra_hosts)
@@ -772,7 +778,9 @@ class DockerVM(BaseNode):
except DockerHttp409Error:
# Container name already exists. This can happen when the server crashes
# and leaves containers behind. Try to remove the conflicting container.
log.warning(f"Container name '{self.docker_name}' is already in use, attempting to clean up the stale container...")
log.warning(
f"Container name '{self.docker_name}' is already in use, attempting to clean up the stale container..."
)
try:
# Try to get and remove the conflicting container
try:
@@ -850,11 +858,13 @@ class DockerVM(BaseNode):
on_host, in_container, permissions = parts
else:
continue
formatted.append({
"PathOnHost": on_host,
"PathInContainer": in_container,
"CgroupPermissions": permissions,
})
formatted.append(
{
"PathOnHost": on_host,
"PathInContainer": in_container,
"CgroupPermissions": permissions,
}
)
return formatted
async def update(self):
@@ -897,7 +907,6 @@ class DockerVM(BaseNode):
await self._start_interface_monitor()
return
else:
if self._console_type == "vnc" and not self._vnc_process:
# restart the vnc process in case it had previously crashed
await self._start_vnc_process(restart=True)
@@ -1042,7 +1051,9 @@ class DockerVM(BaseNode):
stderr = (await process.stderr.read()).decode(errors="replace").strip()
log.error(
"Failed to fix permissions on '%s' for container '%s': %s",
volume, self._name, stderr or f"exit code {process.returncode}"
volume,
self._name,
stderr or f"exit code {process.returncode}",
)
else:
self._permissions_fixed = True
@@ -1102,7 +1113,9 @@ class DockerVM(BaseNode):
log.warning(f"Docker container '{self._name}': cannot access resources to reclaim '{directory}': {e}")
return False
log.info(f"Docker container '{self._name}': reclaiming root-owned files under '{directory}' via a one-shot container")
log.info(
f"Docker container '{self._name}': reclaiming root-owned files under '{directory}' via a one-shot container"
)
# Prefer the image's own chown over the static busybox one: busybox's
# chown dlopens NSS modules from the image, which mismatch the static
# glibc and abort on NOS images whose glibc differs (same reasoning
@@ -1116,12 +1129,24 @@ class DockerVM(BaseNode):
image_ref = self._image_id or self._image
try:
process = await asyncio.subprocess.create_subprocess_exec(
"docker", "run", "--rm", "--network", "none", "--pull", "never", "--user", "0:0",
"--entrypoint", "/gns3/bin/busybox",
"-v", f"{resources_path}:/gns3:ro",
"-v", f"{directory}:/target",
"docker",
"run",
"--rm",
"--network",
"none",
"--pull",
"never",
"--user",
"0:0",
"--entrypoint",
"/gns3/bin/busybox",
"-v",
f"{resources_path}:/gns3:ro",
"-v",
f"{directory}:/target",
image_ref,
"sh", "-c",
"sh",
"-c",
"/gns3/bin/busybox chmod -R u+rwX /target"
f" && ( command -v chown >/dev/null 2>&1 && chown {uid}:{gid} -R /target"
f" || /gns3/bin/busybox chown {uid}:{gid} -R /target )",
@@ -1159,17 +1184,27 @@ class DockerVM(BaseNode):
if tigervnc_path:
with open(os.path.join(self.working_dir, "vnc.log"), "w") as fd:
self._vnc_process = await asyncio.create_subprocess_exec(tigervnc_path,
"-extension", "MIT-SHM",
"-geometry", self._console_resolution,
"-depth", "16",
"-interface", self._manager.port_manager.console_host,
"-rfbport", str(self.console),
"-AlwaysShared",
"-SecurityTypes", "None",
"-desktop", self.name,
":{}".format(self._display),
stdout=fd, stderr=subprocess.STDOUT)
self._vnc_process = await asyncio.create_subprocess_exec(
tigervnc_path,
"-extension",
"MIT-SHM",
"-geometry",
self._console_resolution,
"-depth",
"16",
"-interface",
self._manager.port_manager.console_host,
"-rfbport",
str(self.console),
"-AlwaysShared",
"-SecurityTypes",
"None",
"-desktop",
self.name,
":{}".format(self._display),
stdout=fd,
stderr=subprocess.STDOUT,
)
async def _start_vnc(self):
"""
@@ -1576,8 +1611,8 @@ class DockerVM(BaseNode):
script = (
"while :; do "
"for ifname do "
"flags=$(/gns3/bin/busybox cat \"/sys/class/net/$ifname/flags\" 2>/dev/null) || continue; "
"/gns3/bin/busybox printf '%s=%s\\n' \"$ifname\" \"$flags\"; "
'flags=$(/gns3/bin/busybox cat "/sys/class/net/$ifname/flags" 2>/dev/null) || continue; '
'/gns3/bin/busybox printf \'%s=%s\\n\' "$ifname" "$flags"; '
"done; "
"/gns3/bin/busybox sleep 1; "
"done"
@@ -1621,7 +1656,7 @@ class DockerVM(BaseNode):
asyncio.IncompleteReadError,
asyncio.TimeoutError,
) as e:
if 'writer' in locals():
if "writer" in locals():
await self._close_interface_monitor_writer(writer)
log.warning("Could not monitor interfaces for Docker container '%s': %s", self.name, e)
return
@@ -1658,8 +1693,7 @@ class DockerVM(BaseNode):
"""Read ``ifname=flags`` records and emit changed adapter states."""
interfaces = {
self._get_container_ifname(adapter_number): adapter_number
for adapter_number in range(self.adapters)
self._get_container_ifname(adapter_number): adapter_number for adapter_number in range(self.adapters)
}
try:
while True:
@@ -1747,9 +1781,7 @@ class DockerVM(BaseNode):
await self._ubridge_send(f"bridge create {bridge_name}")
self._bridges.add(bridge_name)
await self._ubridge_send(
"bridge add_nio_tap {bridge_name} {hostif} off".format(
bridge_name=bridge_name, hostif=adapter.host_ifc
)
"bridge add_nio_tap {bridge_name} {hostif} off".format(bridge_name=bridge_name, hostif=adapter.host_ifc)
)
mac_address = int_to_macaddress(macaddress_to_int(self._mac_address) + adapter_number)
@@ -1759,17 +1791,14 @@ class DockerVM(BaseNode):
mac_address = custom_mac_address
try:
await self._ubridge_send('docker set_mac_addr {ifc} {mac}'.format(ifc=adapter.host_ifc, mac=mac_address))
await self._ubridge_send("docker set_mac_addr {ifc} {mac}".format(ifc=adapter.host_ifc, mac=mac_address))
except UbridgeError:
log.warning(f"Could not set MAC address {mac_address} on interface {adapter.host_ifc}")
ifname = self._get_container_ifname(adapter_number)
log.debug(f"Move container {self.name} adapter {adapter.host_ifc} -> {ifname} in ns {self._namespace}")
try:
await self._ubridge_send(
f"docker move_to_ns {adapter.host_ifc} {self._namespace} {ifname}"
)
await self._ubridge_send(f"docker move_to_ns {adapter.host_ifc} {self._namespace} {ifname}")
except UbridgeError as e:
raise UbridgeNamespaceError(e)
else:
@@ -2061,6 +2090,6 @@ class DockerVM(BaseNode):
raise ComputeError(
f"Could not delete the node directory '{self.working_dir}': files left owned by "
f"another user could not be reclaimed ({e}). Reclaim them manually with: "
f"docker run --rm --user 0:0 -v \"{self.working_dir}\":/target --entrypoint /bin/sh "
f'docker run --rm --user 0:0 -v "{self.working_dir}":/target --entrypoint /bin/sh '
f"{self._image} -c 'chown -R {os.getuid()}:{os.getgid()} /target'"
)