Implementet a smarter node_type system

This commit is contained in:
UmmmAGoodName 2026-03-11 18:49:36 +01:00
parent 4a45a68703
commit 19503ab4f7
3 changed files with 55 additions and 38 deletions

View File

@ -27,6 +27,7 @@ from .controller_error import (
ComputeError,
ComputeConflictError
)
from .node_types import BUILTIN_NODE_TYPES
from .ports.port_factory import PortFactory, StandardPortFactory, DynamipsPortFactory
from ..utils.images import images_directories
from ..utils import macaddress_to_int, int_to_macaddress
@ -452,8 +453,7 @@ class Node:
if (
prop == "name"
and self.status == "started"
and self._node_type
not in ("cloud", "nat", "ethernet_switch", "ethernet_hub", "frame_relay_switch", "atm_switch")
and self._node_type not in BUILTIN_NODE_TYPES
):
raise ControllerError("Sorry, it is not possible to rename a node that is already powered on")
setattr(self, prop, kwargs[prop])
@ -541,35 +541,22 @@ class Node:
if self._console:
# console is optional for builtin nodes
data["console"] = self._console
if self._console_type and self._node_type not in (
"cloud",
"nat",
"ethernet_hub",
"frame_relay_switch",
"atm_switch",
):
if self._console_type and self._node_type not in (BUILTIN_NODE_TYPES - {"ethernet_switch"}):
# console_type is not supported by all builtin nodes excepting Ethernet switch
data["console_type"] = self._console_type
if self._aux:
# aux is optional for builtin nodes
data["aux"] = self._aux
if self._aux_type and self._node_type not in (
"cloud",
"nat",
"ethernet_switch",
"ethernet_hub",
"frame_relay_switch",
"atm_switch",
):
if self._aux_type and self._node_type not in BUILTIN_NODE_TYPES:
# aux_type is not supported by all builtin nodes
data["aux_type"] = self._aux_type
if self.custom_adapters:
data["custom_adapters"] = self.custom_adapters
# None properties are not be sent because it can mean the emulator doesn't support it
for key in list(data.keys()):
if data[key] is None or data[key] == {} or key in self.CONTROLLER_ONLY_PROPERTIES:
del data[key]
for key, value in list(data.items()):
if value is None or value == {} or key in self.CONTROLLER_ONLY_PROPERTIES:
del value
return data

View File

@ -0,0 +1,31 @@
#!/usr/bin/env python
#
# Copyright (C) 2026 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Shared node type constants used across the controller.
"""
# Node types that are always running (builtin/virtual switch nodes).
# These nodes do not require explicit start/stop and have limited feature support.
BUILTIN_NODE_TYPES = frozenset({
"cloud",
"nat",
"ethernet_switch",
"ethernet_hub",
"frame_relay_switch",
"atm_switch",
})

View File

@ -18,6 +18,7 @@
from .controller_error import ControllerError, ControllerNotFoundError
from .link import Link
from .node_types import BUILTIN_NODE_TYPES
class UDPLink(Link):
@ -32,6 +33,18 @@ class UDPLink(Link):
Use for the debug exports
"""
return self._link_data
def _get_node_filters(self, node1, node2):
"""
Determine which node gets the active filters applied.
:returns: Tuple of (node1_filters, node2_filters)
"""
filter_node = self._get_filter_node()
return (
self.get_active_filters() if filter_node == node1 else {},
self.get_active_filters() if filter_node == node2 else {},
)
async def create(self):
"""
@ -57,13 +70,7 @@ class UDPLink(Link):
response = await node2.compute.post(f"/projects/{self._project.id}/ports/udp")
self._node2_port = response.json["udp_port"]
node1_filters = {}
node2_filters = {}
filter_node = self._get_filter_node()
if filter_node == node1:
node1_filters = self.get_active_filters()
elif filter_node == node2:
node2_filters = self.get_active_filters()
node1_filters, node2_filters = self._get_node_filters(node1, node2)
# Create the tunnel on both side
self._link_data.append(
@ -108,13 +115,7 @@ class UDPLink(Link):
node1 = self._nodes[0]["node"]
node2 = self._nodes[1]["node"]
node1_filters = {}
node2_filters = {}
filter_node = self._get_filter_node()
if filter_node == node1:
node1_filters = self.get_active_filters()
elif filter_node == node2:
node2_filters = self.get_active_filters()
node1_filters, node2_filters = self._get_node_filters(node1, node2)
adapter_number1 = self._nodes[0]["adapter_number"]
port_number1 = self._nodes[0]["port_number"]
@ -213,18 +214,16 @@ class UDPLink(Link):
:returns: Node where the capture should run
"""
ALWAYS_RUNNING_NODES_TYPE = ("cloud", "nat", "ethernet_switch", "ethernet_hub", "frame_relay_switch", "atm_switch")
for node in self._nodes:
if (
node["node"].compute.id == "local"
and node["node"].node_type in ALWAYS_RUNNING_NODES_TYPE
and node["node"].node_type in BUILTIN_NODE_TYPES
and node["node"].status == "started"
):
return node
for node in self._nodes:
if node["node"].node_type in ALWAYS_RUNNING_NODES_TYPE and node["node"].status == "started":
if node["node"].node_type in BUILTIN_NODE_TYPES and node["node"].status == "started":
return node
for node in self._nodes: