mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-09-08 11:05:33 +03:00
fix: keep port_number in Docker NIO dispatch of the batch endpoints
The project-open bulk path (_add_nio_binding / _get_existing_nio / _update_nio_binding in routes/compute/projects.py) dropped port_number for Docker nodes, unlike the per-node routes and the IOU branch. With multi-port docker adapters (iol-runner nodes model 4 ports per adapter, 0ca9ccc63) every batched NIO landed on port 0 where Adapter.add_nio() silently overwrites — the last entry per node won — so reopening a project clobbered the port-0 links with the port-1 NIOs: links ended up cross-wired between the wrong node pairs and the real links died (IOL direct-link ping failures after close/reopen, EXCESSCOLL storms from the phantom loops).
This commit is contained in:
parent
a8bec35ef0
commit
a8c96dd3f7
@ -144,8 +144,14 @@ async def _add_nio_binding(node, adapter_number, port_number, nio):
|
||||
|
||||
manager_name = type(node.manager).__name__
|
||||
# Adapter-based nodes: docker / qemu / vmware / virtualbox take
|
||||
# (adapter_number, nio); iou additionally takes port_number.
|
||||
if manager_name in ("Docker", "Qemu", "VMware", "VirtualBox"):
|
||||
# (adapter_number, nio); iou additionally takes port_number. Docker
|
||||
# adapters can be multi-port (e.g. iol-runner nodes model 4 ports per
|
||||
# adapter): dropping port_number would bind every NIO to port 0, where
|
||||
# add_nio() silently overwrites — the last entry per node wins and links
|
||||
# end up cross-wired (observed as dead direct links after reopen).
|
||||
if manager_name == "Docker":
|
||||
await node.adapter_add_nio_binding(adapter_number, nio, port_number)
|
||||
elif manager_name in ("Qemu", "VMware", "VirtualBox"):
|
||||
await node.adapter_add_nio_binding(adapter_number, nio)
|
||||
elif manager_name == "IOU":
|
||||
await node.adapter_add_nio_binding(adapter_number, port_number, nio)
|
||||
@ -176,7 +182,9 @@ def _get_existing_nio(node, adapter_number, port_number):
|
||||
"""
|
||||
|
||||
manager_name = type(node.manager).__name__
|
||||
if manager_name in ("Docker", "Qemu", "VMware", "VirtualBox"):
|
||||
if manager_name == "Docker":
|
||||
return node.get_nio(adapter_number, port_number)
|
||||
elif manager_name in ("Qemu", "VMware", "VirtualBox"):
|
||||
return node.get_nio(adapter_number)
|
||||
elif manager_name == "IOU":
|
||||
return node.get_nio(adapter_number, port_number)
|
||||
@ -207,7 +215,9 @@ async def _update_nio_binding(node, adapter_number, port_number, nio):
|
||||
"""
|
||||
|
||||
manager_name = type(node.manager).__name__
|
||||
if manager_name in ("Docker", "Qemu", "VMware", "VirtualBox"):
|
||||
if manager_name == "Docker":
|
||||
await node.adapter_update_nio_binding(adapter_number, nio, port_number)
|
||||
elif manager_name in ("Qemu", "VMware", "VirtualBox"):
|
||||
await node.adapter_update_nio_binding(adapter_number, nio)
|
||||
elif manager_name == "IOU":
|
||||
await node.adapter_update_nio_binding(adapter_number, port_number, nio)
|
||||
|
||||
@ -315,6 +315,37 @@ class TestBatchNIOEdgeCases:
|
||||
await _add_nio_binding(node, 1, 2, nio)
|
||||
node.adapter_add_nio_binding.assert_called_once_with(1, 2, nio)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_docker_dispatch_keeps_port_number(self):
|
||||
"""
|
||||
Docker adapters can be multi-port (iol-runner nodes model 4 ports per
|
||||
adapter). Dropping port_number binds every NIO to port 0 where
|
||||
add_nio() silently overwrites — reopened projects then end up with
|
||||
cross-wired links (the last entry per node wins).
|
||||
"""
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
from gns3server.api.routes.compute.projects import (
|
||||
_add_nio_binding,
|
||||
_get_existing_nio,
|
||||
_update_nio_binding,
|
||||
)
|
||||
|
||||
node = MagicMock()
|
||||
type(node.manager).__name__ = "Docker"
|
||||
node.adapter_add_nio_binding = AsyncMock()
|
||||
node.adapter_update_nio_binding = AsyncMock()
|
||||
nio = MagicMock()
|
||||
node.get_nio = MagicMock(return_value=nio)
|
||||
|
||||
await _add_nio_binding(node, 0, 1, nio)
|
||||
node.adapter_add_nio_binding.assert_called_once_with(0, nio, 1)
|
||||
|
||||
assert _get_existing_nio(node, 0, 1) is nio
|
||||
node.get_nio.assert_called_once_with(0, 1)
|
||||
|
||||
await _update_nio_binding(node, 0, 1, nio)
|
||||
node.adapter_update_nio_binding.assert_called_once_with(0, nio, 1)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_vpcs_dispatch_to_port_add_nio_binding(self):
|
||||
"""_add_nio_binding dispatches VPCS to port_add_nio_binding."""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user