From f6777064db3e3c32cdea897000aedd3b95553141 Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Wed, 25 Feb 2026 22:21:05 +0800 Subject: [PATCH 1/4] feat(ports): add null checks for port name in short name generation Add conditional checks to ensure `self._name` is not None before performing string operations in the `short_name` property. This prevents potential AttributeError exceptions when port name is undefined, improving robustness and compatibility with edge cases in port configuration. --- gns3server/controller/ports/port.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gns3server/controller/ports/port.py b/gns3server/controller/ports/port.py index e0a0406ba..9d45cbda1 100644 --- a/gns3server/controller/ports/port.py +++ b/gns3server/controller/ports/port.py @@ -83,9 +83,9 @@ class Port: # If port name format has changed we use the port name as the short name (1.X behavior) if self._short_name: return self._short_name - elif "/" in self._name: + elif self._name and "/" in self._name: return self._name.replace(self.long_name_type(), self.short_name_type()) - elif self._name.startswith(f"{self.long_name_type()}{self._interface_number}"): + elif self._name and self._name.startswith(f"{self.long_name_type()}{self._interface_number}"): return self.short_name_type() + f"{self._interface_number}" return self._name From cde4bdc114a42347d40501c880f9fd91ef11979a Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Wed, 25 Feb 2026 22:41:22 +0800 Subject: [PATCH 2/4] feat: simplify port name assignment logic Refactor port name assignment to use `or` operator for fallback values, improving code readability and consistency. Changes applied in `node.py` and `port_factory.py` to handle custom adapter settings more cleanly. --- gns3server/controller/node.py | 3 +-- gns3server/controller/ports/port_factory.py | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/gns3server/controller/node.py b/gns3server/controller/node.py index 8622b23b7..0d9e0d91d 100644 --- a/gns3server/controller/node.py +++ b/gns3server/controller/node.py @@ -761,8 +761,7 @@ class Node: if custom_adapter["adapter_number"] == adapter_number: custom_adapter_settings = custom_adapter break - port_name = f"eth{adapter_number}" - port_name = custom_adapter_settings.get("port_name", port_name) + port_name = custom_adapter_settings.get("port_name") or f"eth{adapter_number}" mac_address = custom_adapter_settings.get("mac_address") if not mac_address and "mac_address" in self._properties: mac_address = int_to_macaddress(macaddress_to_int(self._properties["mac_address"]) + adapter_number) diff --git a/gns3server/controller/ports/port_factory.py b/gns3server/controller/ports/port_factory.py index 070e391cf..27b2c7421 100644 --- a/gns3server/controller/ports/port_factory.py +++ b/gns3server/controller/ports/port_factory.py @@ -75,13 +75,13 @@ class StandardPortFactory: for port_number in range(0, port_by_adapter): if first_port_name and adapter_number == 0: - port_name = custom_adapter_settings.get("port_name", first_port_name) + port_name = custom_adapter_settings.get("port_name") or first_port_name port = PortFactory( port_name, segment_number, adapter_number, port_number, "ethernet", short_name=port_name ) else: try: - port_name = port_name_format.format( + default_port_name = port_name_format.format( interface_number, segment_number, adapter=adapter_number, @@ -90,7 +90,7 @@ class StandardPortFactory: except (IndexError, ValueError, KeyError) as e: raise ControllerError(f"Invalid port name format {port_name_format}: {str(e)}") - port_name = custom_adapter_settings.get("port_name", port_name) + port_name = custom_adapter_settings.get("port_name") or default_port_name port = PortFactory(port_name, segment_number, adapter_number, port_number, "ethernet") interface_number += 1 if port_segment_size: From c55fd9e06606996265faf5867e4ba405a55e9243 Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Thu, 26 Feb 2026 09:57:51 +0800 Subject: [PATCH 3/4] feat(virtualbox): add fallback for VBoxManage executable detection Add an additional fallback check for the VBoxManage executable using the capitalized "VBoxManage" command name. This improves compatibility on systems where the executable may be case-sensitive or installed with a different naming convention, ensuring the VirtualBox manager can locate the necessary binary when the lowercase "vboxmanage" is not found. --- gns3server/compute/virtualbox/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gns3server/compute/virtualbox/__init__.py b/gns3server/compute/virtualbox/__init__.py index 5627fb5ef..ccc5a6952 100644 --- a/gns3server/compute/virtualbox/__init__.py +++ b/gns3server/compute/virtualbox/__init__.py @@ -68,6 +68,8 @@ class VirtualBox(BaseManager): vboxmanage_path = vboxmanage_path_osx if not vboxmanage_path: vboxmanage_path = shutil.which("vboxmanage") + if not vboxmanage_path: + vboxmanage_path = shutil.which("VBoxManage") if vboxmanage_path and not os.path.exists(vboxmanage_path): log.error(f"VBoxManage path '{vboxmanage_path}' doesn't exist") From a343ace637a83f7a5768a252a298333afc402873 Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Fri, 27 Feb 2026 00:12:30 +0800 Subject: [PATCH 4/4] Revert: restore original port name handling logic --- gns3server/controller/node.py | 3 ++- gns3server/controller/ports/port.py | 4 ++-- gns3server/controller/ports/port_factory.py | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/gns3server/controller/node.py b/gns3server/controller/node.py index 0d9e0d91d..8622b23b7 100644 --- a/gns3server/controller/node.py +++ b/gns3server/controller/node.py @@ -761,7 +761,8 @@ class Node: if custom_adapter["adapter_number"] == adapter_number: custom_adapter_settings = custom_adapter break - port_name = custom_adapter_settings.get("port_name") or f"eth{adapter_number}" + port_name = f"eth{adapter_number}" + port_name = custom_adapter_settings.get("port_name", port_name) mac_address = custom_adapter_settings.get("mac_address") if not mac_address and "mac_address" in self._properties: mac_address = int_to_macaddress(macaddress_to_int(self._properties["mac_address"]) + adapter_number) diff --git a/gns3server/controller/ports/port.py b/gns3server/controller/ports/port.py index 9d45cbda1..e0a0406ba 100644 --- a/gns3server/controller/ports/port.py +++ b/gns3server/controller/ports/port.py @@ -83,9 +83,9 @@ class Port: # If port name format has changed we use the port name as the short name (1.X behavior) if self._short_name: return self._short_name - elif self._name and "/" in self._name: + elif "/" in self._name: return self._name.replace(self.long_name_type(), self.short_name_type()) - elif self._name and self._name.startswith(f"{self.long_name_type()}{self._interface_number}"): + elif self._name.startswith(f"{self.long_name_type()}{self._interface_number}"): return self.short_name_type() + f"{self._interface_number}" return self._name diff --git a/gns3server/controller/ports/port_factory.py b/gns3server/controller/ports/port_factory.py index 27b2c7421..070e391cf 100644 --- a/gns3server/controller/ports/port_factory.py +++ b/gns3server/controller/ports/port_factory.py @@ -75,13 +75,13 @@ class StandardPortFactory: for port_number in range(0, port_by_adapter): if first_port_name and adapter_number == 0: - port_name = custom_adapter_settings.get("port_name") or first_port_name + port_name = custom_adapter_settings.get("port_name", first_port_name) port = PortFactory( port_name, segment_number, adapter_number, port_number, "ethernet", short_name=port_name ) else: try: - default_port_name = port_name_format.format( + port_name = port_name_format.format( interface_number, segment_number, adapter=adapter_number, @@ -90,7 +90,7 @@ class StandardPortFactory: except (IndexError, ValueError, KeyError) as e: raise ControllerError(f"Invalid port name format {port_name_format}: {str(e)}") - port_name = custom_adapter_settings.get("port_name") or default_port_name + port_name = custom_adapter_settings.get("port_name", port_name) port = PortFactory(port_name, segment_number, adapter_number, port_number, "ethernet") interface_number += 1 if port_segment_size: