From ddf7d4ca6025132d3e9543b9ad8e839438c11e2c Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Sun, 19 Jul 2026 17:41:37 +0800 Subject: [PATCH] fix(controller): refresh cloud/nat node interfaces from compute on GET Cloud and NAT nodes need live host network interface data. Previously, GET /projects/{project_id}/nodes/{node_id} returned cached properties from creation time, so newly added host interfaces (e.g. kernel bridges created by EthernetSwitch nodes) were invisible until the node was deleted and recreated. Now the controller fetches fresh data from the compute node before returning the response, so host interface changes are reflected immediately. Falls back to cached data if compute is unreachable. --- gns3server/api/routes/controller/nodes.py | 13 ++++++++++++- gns3server/controller/node.py | 8 ++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/gns3server/api/routes/controller/nodes.py b/gns3server/api/routes/controller/nodes.py index 413839459..d0b27f81f 100644 --- a/gns3server/api/routes/controller/nodes.py +++ b/gns3server/api/routes/controller/nodes.py @@ -243,14 +243,25 @@ async def reload_all_nodes(project: Project = Depends(dep_project)) -> None: raise +# Node types that need live host interface data from compute +_HOST_INTERFACE_NODE_TYPES = {"cloud", "nat"} + + @router.get("/{node_id}", response_model=schemas.Node, dependencies=[Depends(has_privilege("Node.Audit"))]) -def get_node(node: Node = Depends(dep_node)) -> schemas.Node: +async def get_node(node: Node = Depends(dep_node)) -> schemas.Node: """ Return a node from a given project. Required privilege: Node.Audit """ + if node.node_type in _HOST_INTERFACE_NODE_TYPES: + try: + response = await node.get() + await node.parse_node_response(response.json) + except Exception: + # If compute is unreachable, still return cached data + log.warning(f"Could not refresh node {node.id} from compute, returning cached data") return node.asdict() diff --git a/gns3server/controller/node.py b/gns3server/controller/node.py index 3378f055f..2046c7cd0 100644 --- a/gns3server/controller/node.py +++ b/gns3server/controller/node.py @@ -639,6 +639,14 @@ class Node: except asyncio.TimeoutError: raise ControllerTimeoutError(f"Timeout when reset console {self._name}") + async def get(self, path="", **kwargs): + """ + HTTP get on the node + """ + return await self._compute.get( + f"/projects/{self._project.id}/{self._node_type}/nodes/{self._id}{path}", **kwargs + ) + async def post(self, path, data=None, **kwargs): """ HTTP post on the node