mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 05:51:15 +02:00
refactor: ruff autofixes
This commit is contained in:
455 files changed
+12322
-14762
No files matched your search
@@ -27,6 +27,7 @@ from tests.utils import asyncio_patch
|
||||
|
||||
pytestmark = pytest.mark.asyncio
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def nio():
|
||||
|
||||
@@ -63,19 +64,39 @@ async def test_json_with_ports(on_gns3vm, compute_project, manager):
|
||||
"remote_console_type": "none",
|
||||
"status": "stopped",
|
||||
"node_directory": cloud.working_dir,
|
||||
"ports_mapping": [
|
||||
{
|
||||
"interface": "virbr0",
|
||||
"name": "virbr0",
|
||||
"port_number": 0,
|
||||
"type": "ethernet"
|
||||
}
|
||||
],
|
||||
"ports_mapping": [{"interface": "virbr0", "name": "virbr0", "port_number": 0, "type": "ethernet"}],
|
||||
"interfaces": [
|
||||
{'name': 'eth0', 'special': False, 'type': 'ethernet', 'ip_addresses': [], 'status': 'up', 'speed': 1000, 'mtu': 1500, 'flags': ['up', 'broadcast', 'running', 'multicast']},
|
||||
{'name': 'eth1', 'special': False, 'type': 'ethernet', 'ip_addresses': [], 'status': 'down', 'speed': 0, 'mtu': 1500, 'flags': ['broadcast']},
|
||||
{'name': 'virbr0', 'special': True, 'type': 'ethernet', 'ip_addresses': [], 'status': 'up', 'speed': 10000, 'mtu': 1500, 'flags': ['up', 'broadcast', 'running', 'multicast']}
|
||||
]
|
||||
{
|
||||
"name": "eth0",
|
||||
"special": False,
|
||||
"type": "ethernet",
|
||||
"ip_addresses": [],
|
||||
"status": "up",
|
||||
"speed": 1000,
|
||||
"mtu": 1500,
|
||||
"flags": ["up", "broadcast", "running", "multicast"],
|
||||
},
|
||||
{
|
||||
"name": "eth1",
|
||||
"special": False,
|
||||
"type": "ethernet",
|
||||
"ip_addresses": [],
|
||||
"status": "down",
|
||||
"speed": 0,
|
||||
"mtu": 1500,
|
||||
"flags": ["broadcast"],
|
||||
},
|
||||
{
|
||||
"name": "virbr0",
|
||||
"special": True,
|
||||
"type": "ethernet",
|
||||
"ip_addresses": [],
|
||||
"status": "up",
|
||||
"speed": 10000,
|
||||
"mtu": 1500,
|
||||
"flags": ["up", "broadcast", "running", "multicast"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -97,24 +118,41 @@ async def test_json_without_ports(on_gns3vm, compute_project, manager):
|
||||
"status": "stopped",
|
||||
"node_directory": cloud.working_dir,
|
||||
"ports_mapping": [
|
||||
{
|
||||
"interface": "eth0",
|
||||
"name": "eth0",
|
||||
"port_number": 0,
|
||||
"type": "ethernet"
|
||||
},
|
||||
{
|
||||
"interface": "eth1",
|
||||
"name": "eth1",
|
||||
"port_number": 1,
|
||||
"type": "ethernet"
|
||||
}
|
||||
{"interface": "eth0", "name": "eth0", "port_number": 0, "type": "ethernet"},
|
||||
{"interface": "eth1", "name": "eth1", "port_number": 1, "type": "ethernet"},
|
||||
],
|
||||
"interfaces": [
|
||||
{'name': 'eth0', 'special': False, 'type': 'ethernet', 'ip_addresses': [], 'status': 'up', 'speed': 1000, 'mtu': 1500, 'flags': ['up', 'broadcast', 'running', 'multicast']},
|
||||
{'name': 'eth1', 'special': False, 'type': 'ethernet', 'ip_addresses': [], 'status': 'down', 'speed': 0, 'mtu': 1500, 'flags': ['broadcast']},
|
||||
{'name': 'virbr0', 'special': True, 'type': 'ethernet', 'ip_addresses': [], 'status': 'up', 'speed': 10000, 'mtu': 1500, 'flags': ['up', 'broadcast', 'running', 'multicast']}
|
||||
]
|
||||
{
|
||||
"name": "eth0",
|
||||
"special": False,
|
||||
"type": "ethernet",
|
||||
"ip_addresses": [],
|
||||
"status": "up",
|
||||
"speed": 1000,
|
||||
"mtu": 1500,
|
||||
"flags": ["up", "broadcast", "running", "multicast"],
|
||||
},
|
||||
{
|
||||
"name": "eth1",
|
||||
"special": False,
|
||||
"type": "ethernet",
|
||||
"ip_addresses": [],
|
||||
"status": "down",
|
||||
"speed": 0,
|
||||
"mtu": 1500,
|
||||
"flags": ["broadcast"],
|
||||
},
|
||||
{
|
||||
"name": "virbr0",
|
||||
"special": True,
|
||||
"type": "ethernet",
|
||||
"ip_addresses": [],
|
||||
"status": "up",
|
||||
"speed": 10000,
|
||||
"mtu": 1500,
|
||||
"flags": ["up", "broadcast", "running", "multicast"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -124,49 +162,22 @@ async def test_update_port_mappings(on_gns3vm, compute_project):
|
||||
"""
|
||||
|
||||
ports1 = [
|
||||
{
|
||||
"interface": "eth0",
|
||||
"name": "eth0",
|
||||
"port_number": 0,
|
||||
"type": "ethernet"
|
||||
},
|
||||
{
|
||||
"interface": "eth1",
|
||||
"name": "eth1",
|
||||
"port_number": 1,
|
||||
"type": "ethernet"
|
||||
}
|
||||
{"interface": "eth0", "name": "eth0", "port_number": 0, "type": "ethernet"},
|
||||
{"interface": "eth1", "name": "eth1", "port_number": 1, "type": "ethernet"},
|
||||
]
|
||||
cloud = Cloud("cloud1", str(uuid.uuid4()), compute_project, MagicMock(), ports=ports1)
|
||||
assert cloud.ports_mapping == ports1
|
||||
|
||||
ports2 = [
|
||||
{
|
||||
"interface": "eth0",
|
||||
"name": "eth0",
|
||||
"port_number": 0,
|
||||
"type": "ethernet"
|
||||
},
|
||||
{
|
||||
"interface": "eth1",
|
||||
"name": "eth1",
|
||||
"port_number": 2,
|
||||
"type": "ethernet"
|
||||
}
|
||||
{"interface": "eth0", "name": "eth0", "port_number": 0, "type": "ethernet"},
|
||||
{"interface": "eth1", "name": "eth1", "port_number": 2, "type": "ethernet"},
|
||||
]
|
||||
cloud = Cloud("cloud2", str(uuid.uuid4()), compute_project, MagicMock(), ports=ports2)
|
||||
assert cloud.ports_mapping == ports1
|
||||
|
||||
|
||||
async def test_linux_ethernet_raw_add_nio(linux_platform, compute_project, nio):
|
||||
ports = [
|
||||
{
|
||||
"interface": "eth0",
|
||||
"name": "eth0",
|
||||
"port_number": 0,
|
||||
"type": "ethernet"
|
||||
}
|
||||
]
|
||||
ports = [{"interface": "eth0", "name": "eth0", "port_number": 0, "type": "ethernet"}]
|
||||
cloud = Cloud("cloud1", str(uuid.uuid4()), compute_project, MagicMock(), ports=ports)
|
||||
cloud.status = "started"
|
||||
|
||||
@@ -176,43 +187,42 @@ async def test_linux_ethernet_raw_add_nio(linux_platform, compute_project, nio):
|
||||
with patch("gns3server.compute.builtin.nodes.cloud.Cloud._interfaces", return_value=[{"name": "eth0"}]):
|
||||
await cloud.add_nio(nio, 0)
|
||||
|
||||
ubridge_mock.assert_has_calls([
|
||||
call("bridge create {}-0".format(cloud._id)),
|
||||
call("bridge add_nio_udp {}-0 4242 127.0.0.1 4343".format(cloud._id)),
|
||||
call('bridge reset_packet_filters {}-0'.format(cloud._id)),
|
||||
call("bridge add_nio_linux_raw {}-0 \"eth0\"".format(cloud._id)),
|
||||
call("bridge start {}-0".format(cloud._id)),
|
||||
])
|
||||
ubridge_mock.assert_has_calls(
|
||||
[
|
||||
call("bridge create {}-0".format(cloud._id)),
|
||||
call("bridge add_nio_udp {}-0 4242 127.0.0.1 4343".format(cloud._id)),
|
||||
call("bridge reset_packet_filters {}-0".format(cloud._id)),
|
||||
call('bridge add_nio_linux_raw {}-0 "eth0"'.format(cloud._id)),
|
||||
call("bridge start {}-0".format(cloud._id)),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
async def test_linux_ethernet_raw_add_nio_bridge(linux_platform, compute_project, nio):
|
||||
"""
|
||||
Bridge can't be connected directly to a cloud we use a tap in the middle
|
||||
"""
|
||||
ports = [
|
||||
{
|
||||
"interface": "bridge0",
|
||||
"name": "bridge0",
|
||||
"port_number": 0,
|
||||
"type": "ethernet"
|
||||
}
|
||||
]
|
||||
ports = [{"interface": "bridge0", "name": "bridge0", "port_number": 0, "type": "ethernet"}]
|
||||
cloud = Cloud("cloud1", str(uuid.uuid4()), compute_project, MagicMock(), ports=ports)
|
||||
cloud.status = "started"
|
||||
|
||||
with patch("shutil.which", return_value="/bin/ubridge"):
|
||||
with patch("gns3server.compute.base_manager.BaseManager.has_privileged_access", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud._ubridge_send") as ubridge_mock:
|
||||
with patch("gns3server.compute.builtin.nodes.cloud.Cloud._interfaces", return_value=[{"name": "bridge0"}]):
|
||||
with patch(
|
||||
"gns3server.compute.builtin.nodes.cloud.Cloud._interfaces", return_value=[{"name": "bridge0"}]
|
||||
):
|
||||
with patch("gns3server.utils.interfaces.is_interface_bridge", return_value=True):
|
||||
await cloud.add_nio(nio, 0)
|
||||
|
||||
tap = "gns3tap0-0"
|
||||
ubridge_mock.assert_has_calls([
|
||||
call("bridge create {}-0".format(cloud._id)),
|
||||
call("bridge add_nio_udp {}-0 4242 127.0.0.1 4343".format(cloud._id)),
|
||||
call('bridge reset_packet_filters {}-0'.format(cloud._id)),
|
||||
call("bridge add_nio_tap \"{}-0\" \"{}\"".format(cloud._id, tap)),
|
||||
call("brctl addif \"bridge0\" \"{}\"".format(tap)),
|
||||
call("bridge start {}-0".format(cloud._id)),
|
||||
])
|
||||
ubridge_mock.assert_has_calls(
|
||||
[
|
||||
call("bridge create {}-0".format(cloud._id)),
|
||||
call("bridge add_nio_udp {}-0 4242 127.0.0.1 4343".format(cloud._id)),
|
||||
call("bridge reset_packet_filters {}-0".format(cloud._id)),
|
||||
call('bridge add_nio_tap "{}-0" "{}"'.format(cloud._id, tap)),
|
||||
call('brctl addif "bridge0" "{}"'.format(tap)),
|
||||
call("bridge start {}-0".format(cloud._id)),
|
||||
]
|
||||
)
|
||||
@@ -30,14 +30,7 @@ def test_json_gns3vm(on_gns3vm, compute_project):
|
||||
"node_id": nat.id,
|
||||
"project_id": compute_project.id,
|
||||
"status": "started",
|
||||
"ports_mapping": [
|
||||
{
|
||||
"interface": "virbr0",
|
||||
"name": "nat0",
|
||||
"port_number": 0,
|
||||
"type": "ethernet"
|
||||
}
|
||||
],
|
||||
"ports_mapping": [{"interface": "virbr0", "name": "nat0", "port_number": 0, "type": "ethernet"}],
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "virbr0",
|
||||
@@ -51,9 +44,13 @@ def test_json_gns3vm(on_gns3vm, compute_project):
|
||||
|
||||
def test_json_darwin(darwin_platform, compute_project):
|
||||
|
||||
with patch("gns3server.utils.interfaces.interfaces", return_value=[
|
||||
with patch(
|
||||
"gns3server.utils.interfaces.interfaces",
|
||||
return_value=[
|
||||
{"name": "eth0", "special": False, "type": "ethernet"},
|
||||
{"name": "vmnet8", "special": True, "type": "ethernet"}]):
|
||||
{"name": "vmnet8", "special": True, "type": "ethernet"},
|
||||
],
|
||||
):
|
||||
nat = Nat("nat1", str(uuid.uuid4()), compute_project, MagicMock())
|
||||
assert nat.asdict() == {
|
||||
"name": "nat1",
|
||||
@@ -61,14 +58,7 @@ def test_json_darwin(darwin_platform, compute_project):
|
||||
"node_id": nat.id,
|
||||
"project_id": compute_project.id,
|
||||
"status": "started",
|
||||
"ports_mapping": [
|
||||
{
|
||||
"interface": "vmnet8",
|
||||
"name": "nat0",
|
||||
"port_number": 0,
|
||||
"type": "ethernet"
|
||||
}
|
||||
],
|
||||
"ports_mapping": [{"interface": "vmnet8", "name": "nat0", "port_number": 0, "type": "ethernet"}],
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "vmnet8",
|
||||
@@ -81,8 +71,10 @@ def test_json_darwin(darwin_platform, compute_project):
|
||||
|
||||
|
||||
def test_json_windows_with_full_name_of_interface(windows_platform, project):
|
||||
with patch("gns3server.utils.interfaces.interfaces", return_value=[
|
||||
{"name": "VMware Network Adapter VMnet8", "special": True, "type": "ethernet"}]):
|
||||
with patch(
|
||||
"gns3server.utils.interfaces.interfaces",
|
||||
return_value=[{"name": "VMware Network Adapter VMnet8", "special": True, "type": "ethernet"}],
|
||||
):
|
||||
nat = Nat("nat1", str(uuid.uuid4()), project, MagicMock())
|
||||
assert nat.asdict() == {
|
||||
"name": "nat1",
|
||||
@@ -91,12 +83,7 @@ def test_json_windows_with_full_name_of_interface(windows_platform, project):
|
||||
"project_id": project.id,
|
||||
"status": "started",
|
||||
"ports_mapping": [
|
||||
{
|
||||
"interface": "VMware Network Adapter VMnet8",
|
||||
"name": "nat0",
|
||||
"port_number": 0,
|
||||
"type": "ethernet"
|
||||
}
|
||||
{"interface": "VMware Network Adapter VMnet8", "name": "nat0", "port_number": 0, "type": "ethernet"}
|
||||
],
|
||||
"interfaces": [
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ async def test_query_success(vm):
|
||||
|
||||
response = MagicMock()
|
||||
response.status = 200
|
||||
response.headers = {'CONTENT-TYPE': 'application/json'}
|
||||
response.headers = {"CONTENT-TYPE": "application/json"}
|
||||
|
||||
async def read():
|
||||
return b'{"c": false}'
|
||||
@@ -48,12 +48,14 @@ async def test_query_success(vm):
|
||||
response.read.side_effect = read
|
||||
vm._session.request = AsyncioMagicMock(return_value=response)
|
||||
data = await vm.query("POST", "test", data={"a": True}, params={"b": 1})
|
||||
vm._session.request.assert_called_with('POST',
|
||||
'http://docker/v{}/test'.format(DOCKER_MINIMUM_API_VERSION),
|
||||
data='{"a": true}',
|
||||
headers={'content-type': 'application/json'},
|
||||
params={'b': 1},
|
||||
timeout=300)
|
||||
vm._session.request.assert_called_with(
|
||||
"POST",
|
||||
"http://docker/v{}/test".format(DOCKER_MINIMUM_API_VERSION),
|
||||
data='{"a": true}',
|
||||
headers={"content-type": "application/json"},
|
||||
params={"b": 1},
|
||||
timeout=300,
|
||||
)
|
||||
|
||||
assert data == {"c": False}
|
||||
|
||||
@@ -71,12 +73,14 @@ async def test_query_error(vm):
|
||||
vm._session.request = AsyncioMagicMock(return_value=response)
|
||||
with pytest.raises(DockerError):
|
||||
await vm.query("POST", "test", data={"a": True}, params={"b": 1})
|
||||
vm._session.request.assert_called_with('POST',
|
||||
'http://docker/v{}/test'.format(DOCKER_MINIMUM_API_VERSION),
|
||||
data='{"a": true}',
|
||||
headers={'content-type': 'application/json'},
|
||||
params={'b': 1},
|
||||
timeout=300)
|
||||
vm._session.request.assert_called_with(
|
||||
"POST",
|
||||
"http://docker/v{}/test".format(DOCKER_MINIMUM_API_VERSION),
|
||||
data='{"a": true}',
|
||||
headers={"content-type": "application/json"},
|
||||
params={"b": 1},
|
||||
timeout=300,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -92,12 +96,14 @@ async def test_query_error_json(vm):
|
||||
vm._session.request = AsyncioMagicMock(return_value=response)
|
||||
with pytest.raises(DockerError):
|
||||
await vm.query("POST", "test", data={"a": True}, params={"b": 1})
|
||||
vm._session.request.assert_called_with('POST',
|
||||
'http://docker/v{}/test'.format(DOCKER_MINIMUM_API_VERSION),
|
||||
data='{"a": true}',
|
||||
headers={'content-type': 'application/json'},
|
||||
params={'b': 1},
|
||||
timeout=300)
|
||||
vm._session.request.assert_called_with(
|
||||
"POST",
|
||||
"http://docker/v{}/test".format(DOCKER_MINIMUM_API_VERSION),
|
||||
data='{"a": true}',
|
||||
headers={"content-type": "application/json"},
|
||||
params={"b": 1},
|
||||
timeout=300,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -105,28 +111,20 @@ async def test_list_images():
|
||||
|
||||
response = [
|
||||
{
|
||||
"RepoTags": [
|
||||
"ubuntu:12.04",
|
||||
"ubuntu:precise",
|
||||
"ubuntu:latest"
|
||||
],
|
||||
"RepoTags": ["ubuntu:12.04", "ubuntu:precise", "ubuntu:latest"],
|
||||
"Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c",
|
||||
"Created": 1365714795,
|
||||
"Size": 131506275,
|
||||
"VirtualSize": 131506275
|
||||
"VirtualSize": 131506275,
|
||||
},
|
||||
{
|
||||
"RepoTags": [
|
||||
"ubuntu:12.10",
|
||||
"ubuntu:quantal",
|
||||
"<none>:<none>"
|
||||
],
|
||||
"RepoTags": ["ubuntu:12.10", "ubuntu:quantal", "<none>:<none>"],
|
||||
"ParentId": "27cf784147099545",
|
||||
"Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
|
||||
"Created": 1364102658,
|
||||
"Size": 24653,
|
||||
"VirtualSize": 180116135
|
||||
}
|
||||
"VirtualSize": 180116135,
|
||||
},
|
||||
]
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
|
||||
@@ -196,7 +194,6 @@ async def test_force_pull_image():
|
||||
async def test_pull_image_error():
|
||||
|
||||
class Content:
|
||||
|
||||
def __init__(self):
|
||||
self._chunks = [b'{"error": "image not found"}', b""]
|
||||
|
||||
@@ -217,7 +214,6 @@ async def test_pull_image_error():
|
||||
async def test_pull_image_rejects_incomplete_response():
|
||||
|
||||
class Content:
|
||||
|
||||
def __init__(self):
|
||||
self._read = False
|
||||
|
||||
@@ -241,7 +237,6 @@ async def test_pull_image_rejects_incomplete_response():
|
||||
async def test_pull_image_propagates_timeout():
|
||||
|
||||
class Content:
|
||||
|
||||
async def read(self, size):
|
||||
raise asyncio.TimeoutError
|
||||
|
||||
@@ -259,7 +254,6 @@ async def test_pull_image_propagates_timeout():
|
||||
async def test_load_image():
|
||||
|
||||
class Content:
|
||||
|
||||
def __init__(self):
|
||||
self._chunks = [b'{"stream": "Loaded image ID: sha256:e90e34656806"}', b""]
|
||||
|
||||
@@ -285,7 +279,6 @@ async def test_load_image():
|
||||
async def test_load_image_error():
|
||||
|
||||
class Content:
|
||||
|
||||
def __init__(self):
|
||||
self._chunks = [b'{"error": "invalid tar file"}', b""]
|
||||
|
||||
@@ -307,13 +300,12 @@ async def test_load_image_error():
|
||||
@pytest.mark.asyncio
|
||||
async def test_docker_check_connection_docker_minimum_version(vm):
|
||||
|
||||
response = {
|
||||
'ApiVersion': '1.01',
|
||||
'Version': '1.12'
|
||||
}
|
||||
response = {"ApiVersion": "1.01", "Version": "1.12"}
|
||||
|
||||
with patch("gns3server.compute.docker.Docker.connector"), \
|
||||
asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response):
|
||||
with (
|
||||
patch("gns3server.compute.docker.Docker.connector"),
|
||||
asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response),
|
||||
):
|
||||
vm._connected = False
|
||||
with pytest.raises(DockerError):
|
||||
await vm._check_connection()
|
||||
@@ -323,13 +315,14 @@ async def test_docker_check_connection_docker_minimum_version(vm):
|
||||
async def test_docker_check_connection_docker_preferred_version_against_newer(vm):
|
||||
|
||||
response = {
|
||||
'ApiVersion': '1.52',
|
||||
'Version': '29.0.1',
|
||||
|
||||
"ApiVersion": "1.52",
|
||||
"Version": "29.0.1",
|
||||
}
|
||||
|
||||
with patch("gns3server.compute.docker.Docker.connector"), \
|
||||
asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response):
|
||||
with (
|
||||
patch("gns3server.compute.docker.Docker.connector"),
|
||||
asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response),
|
||||
):
|
||||
vm._connected = False
|
||||
await vm._check_connection()
|
||||
assert vm._api_version == DOCKER_PREFERRED_API_VERSION
|
||||
@@ -338,14 +331,12 @@ async def test_docker_check_connection_docker_preferred_version_against_newer(vm
|
||||
@pytest.mark.asyncio
|
||||
async def test_docker_check_connection_docker_preferred_version_against_older(vm):
|
||||
|
||||
response = {
|
||||
'ApiVersion': '1.43',
|
||||
'Version': '24.0.2',
|
||||
'MinAPIVersion': '1.40'
|
||||
}
|
||||
response = {"ApiVersion": "1.43", "Version": "24.0.2", "MinAPIVersion": "1.40"}
|
||||
|
||||
with patch("gns3server.compute.docker.Docker.connector"), \
|
||||
asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response):
|
||||
with (
|
||||
patch("gns3server.compute.docker.Docker.connector"),
|
||||
asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response),
|
||||
):
|
||||
vm._connected = False
|
||||
await vm._check_connection()
|
||||
assert vm._api_version == DOCKER_MINIMUM_API_VERSION
|
||||
@@ -355,12 +346,14 @@ async def test_docker_check_connection_docker_preferred_version_against_older(vm
|
||||
async def test_docker_check_connection_docker_unsupported_version(vm):
|
||||
|
||||
response = {
|
||||
'ApiVersion': '1.25',
|
||||
'Version': '1.13.1',
|
||||
"ApiVersion": "1.25",
|
||||
"Version": "1.13.1",
|
||||
}
|
||||
|
||||
with patch("gns3server.compute.docker.Docker.connector"), \
|
||||
asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response):
|
||||
with (
|
||||
patch("gns3server.compute.docker.Docker.connector"),
|
||||
asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response),
|
||||
):
|
||||
vm._connected = False
|
||||
with pytest.raises(DockerError) as e:
|
||||
await vm._check_connection()
|
||||
@@ -370,12 +363,14 @@ async def test_docker_check_connection_docker_unsupported_version(vm):
|
||||
async def test_install_busybox():
|
||||
|
||||
mock_process = MagicMock()
|
||||
mock_process.returncode = 1 # means that busybox is not dynamically linked
|
||||
mock_process.returncode = 1 # means that busybox is not dynamically linked
|
||||
mock_process.communicate = AsyncioMagicMock(return_value=(b"", b"not a dynamic executable"))
|
||||
|
||||
with patch("gns3server.compute.docker.os.path.isfile", return_value=False):
|
||||
with patch("gns3server.compute.docker.shutil.which", return_value="/usr/bin/busybox"):
|
||||
with asyncio_patch("gns3server.compute.docker.asyncio.create_subprocess_exec", return_value=mock_process) as create_subprocess_mock:
|
||||
with asyncio_patch(
|
||||
"gns3server.compute.docker.asyncio.create_subprocess_exec", return_value=mock_process
|
||||
) as create_subprocess_mock:
|
||||
with patch("gns3server.compute.docker.shutil.copy2") as copy2_mock:
|
||||
dst_dir = Docker.resources_path()
|
||||
await Docker.install_busybox(dst_dir)
|
||||
@@ -396,12 +391,18 @@ async def test_install_busybox_dynamic_linked():
|
||||
mock_process.communicate = AsyncioMagicMock(return_value=(b"Dynamically linked library", b""))
|
||||
|
||||
with patch("os.path.isfile", return_value=False):
|
||||
with patch("gns3server.compute.docker.shutil.which", side_effect=lambda name: "/usr/bin/busybox" if name == "busybox" else None):
|
||||
with patch(
|
||||
"gns3server.compute.docker.shutil.which",
|
||||
side_effect=lambda name: "/usr/bin/busybox" if name == "busybox" else None,
|
||||
):
|
||||
with asyncio_patch("gns3server.compute.docker.asyncio.create_subprocess_exec", return_value=mock_process):
|
||||
with pytest.raises(DockerError) as e:
|
||||
dst_dir = Docker.resources_path()
|
||||
await Docker.install_busybox(dst_dir)
|
||||
assert str(e.value) == "No busybox executable could be found, please install busybox (apt install busybox-static on Debian/Ubuntu) and make sure it is in your PATH"
|
||||
assert (
|
||||
str(e.value)
|
||||
== "No busybox executable could be found, please install busybox (apt install busybox-static on Debian/Ubuntu) and make sure it is in your PATH"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -412,7 +413,10 @@ async def test_install_busybox_no_executables():
|
||||
with pytest.raises(DockerError) as e:
|
||||
dst_dir = Docker.resources_path()
|
||||
await Docker.install_busybox(dst_dir)
|
||||
assert str(e.value) == "No busybox executable could be found, please install busybox (apt install busybox-static on Debian/Ubuntu) and make sure it is in your PATH"
|
||||
assert (
|
||||
str(e.value)
|
||||
== "No busybox executable could be found, please install busybox (apt install busybox-static on Debian/Ubuntu) and make sure it is in your PATH"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -494,4 +498,4 @@ async def test_check_host_readiness_continues_past_unreadable_key(caplog):
|
||||
|
||||
message = " ".join(r.message for r in caplog.records)
|
||||
assert "max_user_instances=128" in message # collected before the gap
|
||||
assert "modprobe fuse" in message # FUSE check still ran
|
||||
assert "modprobe fuse" in message # FUSE check still ran
|
||||
File diff suppressed because it is too large.
Load diff
@@ -72,13 +72,20 @@ async def manager(port_manager):
|
||||
return m
|
||||
|
||||
|
||||
def _make_vm(compute_project, manager, environment="GNS3_IOL_RUNNER=1",
|
||||
extra_volumes=None, adapters=4, console_type="telnet"):
|
||||
def _make_vm(
|
||||
compute_project, manager, environment="GNS3_IOL_RUNNER=1", extra_volumes=None, adapters=4, console_type="telnet"
|
||||
):
|
||||
"""Build an IOLDockerVM with a fake cid (no create() called)."""
|
||||
vm = IOLDockerVM(
|
||||
"iol-xe-1", str(uuid.uuid4()), compute_project, manager, "iol-xe/iol-xe:17-18-02",
|
||||
console_type=console_type, environment=environment,
|
||||
extra_volumes=extra_volumes or [], adapters=adapters,
|
||||
"iol-xe-1",
|
||||
str(uuid.uuid4()),
|
||||
compute_project,
|
||||
manager,
|
||||
"iol-xe/iol-xe:17-18-02",
|
||||
console_type=console_type,
|
||||
environment=environment,
|
||||
extra_volumes=extra_volumes or [],
|
||||
adapters=adapters,
|
||||
)
|
||||
vm._cid = "e90e34656842"
|
||||
# mirrors the controller flow, which always delivers an allocated id
|
||||
@@ -127,40 +134,37 @@ def _wiring_dir(vm):
|
||||
# Factory selection
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_factory_selects_iol_for_env_marker(manager):
|
||||
|
||||
assert manager._select_node_class(console_type="telnet",
|
||||
environment="GNS3_IOL_RUNNER=1") is IOLDockerVM
|
||||
assert manager._select_node_class(console_type="telnet", environment="GNS3_IOL_RUNNER=1") is IOLDockerVM
|
||||
|
||||
|
||||
def test_factory_tolerates_whitespace_and_comma(manager):
|
||||
|
||||
assert manager._select_node_class(console_type="telnet",
|
||||
environment=" GNS3_IOL_RUNNER=1,\nFOO=bar") is IOLDockerVM
|
||||
assert manager._select_node_class(console_type="telnet", environment=" GNS3_IOL_RUNNER=1,\nFOO=bar") is IOLDockerVM
|
||||
|
||||
|
||||
def test_factory_docker_exec_wins_over_iol_marker(manager):
|
||||
|
||||
assert manager._select_node_class(console_type="docker_exec",
|
||||
environment="GNS3_IOL_RUNNER=1") is VendorDockerVM
|
||||
assert manager._select_node_class(console_type="docker_exec", environment="GNS3_IOL_RUNNER=1") is VendorDockerVM
|
||||
|
||||
|
||||
def test_factory_plain_environment_is_base(manager):
|
||||
|
||||
assert manager._select_node_class(console_type="telnet",
|
||||
environment="FOO=bar\nGNS3_BAZ=nope") is DockerVM
|
||||
assert manager._select_node_class(console_type="telnet", environment="FOO=bar\nGNS3_BAZ=nope") is DockerVM
|
||||
|
||||
|
||||
def test_factory_generic_unix_knob_selects_vendor(manager):
|
||||
|
||||
assert manager._select_node_class(console_type="telnet",
|
||||
environment="GNS3_UNIX_SOCKET_NIO=1") is VendorDockerVM
|
||||
assert manager._select_node_class(console_type="telnet", environment="GNS3_UNIX_SOCKET_NIO=1") is VendorDockerVM
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Knob parsing
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_marker_forces_skip_init_and_unix_nio(compute_project, manager):
|
||||
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_IOL_RUNNER=1")
|
||||
@@ -172,12 +176,10 @@ def test_marker_forces_skip_init_and_unix_nio(compute_project, manager):
|
||||
|
||||
def test_iol_memory_knob(compute_project, manager):
|
||||
|
||||
vm = _make_vm(compute_project, manager,
|
||||
environment="GNS3_IOL_RUNNER=1\nGNS3_IOL_MEMORY=4096")
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_IOL_RUNNER=1\nGNS3_IOL_MEMORY=4096")
|
||||
assert vm._iol_memory == 4096
|
||||
|
||||
vm = _make_vm(compute_project, manager,
|
||||
environment="GNS3_IOL_RUNNER=1\nGNS3_IOL_MEMORY=notanumber")
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_IOL_RUNNER=1\nGNS3_IOL_MEMORY=notanumber")
|
||||
assert vm._iol_memory == 2048
|
||||
|
||||
|
||||
@@ -185,15 +187,13 @@ def test_iol_memory_knob(compute_project, manager):
|
||||
# create()
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_keeps_image_entrypoint(compute_project, manager):
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images",
|
||||
return_value=[{"image": "iol-xe"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query",
|
||||
return_value=_create_response()) as mock:
|
||||
with patch("asyncio.subprocess.create_subprocess_exec",
|
||||
return_value=_seed_proc()):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "iol-xe"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=_create_response()) as mock:
|
||||
with patch("asyncio.subprocess.create_subprocess_exec", return_value=_seed_proc()):
|
||||
vm = _make_vm(compute_project, manager)
|
||||
await vm.create()
|
||||
sent = mock.call_args.kwargs["data"]
|
||||
@@ -205,12 +205,9 @@ async def test_create_keeps_image_entrypoint(compute_project, manager):
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_auto_adds_config_and_tmp_run_volumes(compute_project, manager):
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images",
|
||||
return_value=[{"image": "iol-xe"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query",
|
||||
return_value=_create_response()) as mock:
|
||||
with patch("asyncio.subprocess.create_subprocess_exec",
|
||||
return_value=_seed_proc()):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "iol-xe"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=_create_response()) as mock:
|
||||
with patch("asyncio.subprocess.create_subprocess_exec", return_value=_seed_proc()):
|
||||
vm = _make_vm(compute_project, manager, extra_volumes=[])
|
||||
await vm.create()
|
||||
sent = mock.call_args.kwargs["data"]
|
||||
@@ -235,12 +232,9 @@ async def test_create_start_command_becomes_runner_flags(compute_project, manage
|
||||
|
||||
vm = _make_vm(compute_project, manager)
|
||||
vm.start_command = "-keep"
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images",
|
||||
return_value=[{"image": "iol-xe"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query",
|
||||
return_value=_create_response()) as mock:
|
||||
with patch("asyncio.subprocess.create_subprocess_exec",
|
||||
return_value=_seed_proc()):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "iol-xe"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=_create_response()) as mock:
|
||||
with patch("asyncio.subprocess.create_subprocess_exec", return_value=_seed_proc()):
|
||||
await vm.create()
|
||||
sent = mock.call_args.kwargs["data"]
|
||||
# start_command is the container CMD = extra iol-runner flags
|
||||
@@ -251,6 +245,7 @@ async def test_create_start_command_becomes_runner_flags(compute_project, manage
|
||||
# start() — runtime preparation
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_writes_iol_config(compute_project, manager):
|
||||
|
||||
@@ -402,6 +397,7 @@ async def test_restart_is_graceful_stop_then_start(compute_project, manager):
|
||||
# Wiring — unix-socket NIO
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_ubridge_connection_unix_wiring(compute_project, manager):
|
||||
|
||||
@@ -463,8 +459,7 @@ async def test_add_ubridge_connection_timeout_is_actionable(compute_project, man
|
||||
async def raise_timeout(path, timeout=60):
|
||||
raise asyncio.TimeoutError()
|
||||
|
||||
with patch("gns3server.compute.docker.vendor_docker_vm.wait_for_file_creation",
|
||||
side_effect=raise_timeout):
|
||||
with patch("gns3server.compute.docker.vendor_docker_vm.wait_for_file_creation", side_effect=raise_timeout):
|
||||
with pytest.raises(DockerError) as excinfo:
|
||||
await vm._add_ubridge_connection(None, 0)
|
||||
# the message names the adapter and the exact wiring path
|
||||
@@ -497,6 +492,7 @@ async def test_add_ubridge_connection_without_nio_still_wires(compute_project, m
|
||||
# IOU-style port model — 1 adapter = 4 ethernet ports
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_adapters_are_four_port_units(compute_project, manager):
|
||||
|
||||
vm = _make_vm(compute_project, manager, adapters=2)
|
||||
@@ -523,7 +519,7 @@ async def test_wiring_addresses_ports_within_adapters(compute_project, manager):
|
||||
await vm._add_ubridge_connection(nio, 1, port_number=2)
|
||||
|
||||
flat = "\n".join(str(c) for c in vm._ubridge_hypervisor.method_calls)
|
||||
assert 'bridge add_nio_unix bridge1_2 ' in flat
|
||||
assert "bridge add_nio_unix bridge1_2 " in flat
|
||||
assert f'"{os.path.join(wiring_dir, "c06.sock")}"' in flat
|
||||
assert f'"{os.path.join(wiring_dir, "s06.sock")}"' in flat
|
||||
assert "add_nio_udp bridge1_2 4242 127.0.0.1 4343" in flat
|
||||
@@ -547,33 +543,59 @@ async def test_nio_binding_rejects_port_out_of_range(compute_project, manager):
|
||||
# Generic GNS3_UNIX_SOCKET_NIO knob on plain VendorDockerVM
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_env_unix_socket_nio_parsing(compute_project, manager):
|
||||
|
||||
vm = VendorDockerVM("vendor-1", str(uuid.uuid4()), compute_project, manager, "vendor:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_UNIX_SOCKET_NIO=1\nGNS3_UNIX_SOCKET_DIR=/var/run/socks")
|
||||
vm = VendorDockerVM(
|
||||
"vendor-1",
|
||||
str(uuid.uuid4()),
|
||||
compute_project,
|
||||
manager,
|
||||
"vendor:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_UNIX_SOCKET_NIO=1\nGNS3_UNIX_SOCKET_DIR=/var/run/socks",
|
||||
)
|
||||
assert vm._unix_socket_nio is True
|
||||
assert vm._unix_socket_dir == "/var/run/socks"
|
||||
|
||||
# invalid dirs are rejected, keeping the default
|
||||
vm = VendorDockerVM("vendor-1", str(uuid.uuid4()), compute_project, manager, "vendor:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_UNIX_SOCKET_NIO=yes\nGNS3_UNIX_SOCKET_DIR=../../etc")
|
||||
vm = VendorDockerVM(
|
||||
"vendor-1",
|
||||
str(uuid.uuid4()),
|
||||
compute_project,
|
||||
manager,
|
||||
"vendor:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_UNIX_SOCKET_NIO=yes\nGNS3_UNIX_SOCKET_DIR=../../etc",
|
||||
)
|
||||
assert vm._unix_socket_nio is True
|
||||
assert vm._unix_socket_dir == "/tmp"
|
||||
|
||||
# off by default / explicit off
|
||||
vm = VendorDockerVM("vendor-1", str(uuid.uuid4()), compute_project, manager, "vendor:latest",
|
||||
console_type="docker_exec", environment="GNS3_SKIP_INIT=1")
|
||||
vm = VendorDockerVM(
|
||||
"vendor-1",
|
||||
str(uuid.uuid4()),
|
||||
compute_project,
|
||||
manager,
|
||||
"vendor:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1",
|
||||
)
|
||||
assert vm._unix_socket_nio is False
|
||||
|
||||
|
||||
def test_unix_socket_dir_bound_from_runtime_dir(compute_project, manager):
|
||||
|
||||
vm = VendorDockerVM("vendor-1", str(uuid.uuid4()), compute_project, manager, "vendor:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_UNIX_SOCKET_NIO=1",
|
||||
extra_volumes=[])
|
||||
vm = VendorDockerVM(
|
||||
"vendor-1",
|
||||
str(uuid.uuid4()),
|
||||
compute_project,
|
||||
manager,
|
||||
"vendor:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_UNIX_SOCKET_NIO=1",
|
||||
extra_volumes=[],
|
||||
)
|
||||
# the socket directory is an ephemeral per-node directory from the
|
||||
# runtime dir, not a volume: writable by the (unprivileged) agent and
|
||||
# short enough for AF_UNIX
|
||||
@@ -584,10 +606,16 @@ def test_unix_socket_dir_bound_from_runtime_dir(compute_project, manager):
|
||||
assert socket_binds[0]["Source"] == _wiring_dir(vm)
|
||||
|
||||
# a socket dir already covered by a persisted volume gets no extra bind
|
||||
vm = VendorDockerVM("vendor-1", str(uuid.uuid4()), compute_project, manager, "vendor:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_UNIX_SOCKET_NIO=1",
|
||||
extra_volumes=["/tmp"])
|
||||
vm = VendorDockerVM(
|
||||
"vendor-1",
|
||||
str(uuid.uuid4()),
|
||||
compute_project,
|
||||
manager,
|
||||
"vendor:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_UNIX_SOCKET_NIO=1",
|
||||
extra_volumes=["/tmp"],
|
||||
)
|
||||
binds = vm._mount_binds({"Config": {"Volumes": {}}})
|
||||
assert not any(b.get("Source") == _wiring_dir(vm) for b in binds)
|
||||
assert any(b.get("Target") == "/tmp" for b in binds)
|
||||
@@ -596,9 +624,15 @@ def test_unix_socket_dir_bound_from_runtime_dir(compute_project, manager):
|
||||
@pytest.mark.asyncio
|
||||
async def test_generic_unix_socket_dir_honored_in_wiring(compute_project, manager):
|
||||
|
||||
vm = VendorDockerVM("vendor-1", str(uuid.uuid4()), compute_project, manager, "vendor:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_UNIX_SOCKET_NIO=1\nGNS3_UNIX_SOCKET_DIR=/var/run/socks")
|
||||
vm = VendorDockerVM(
|
||||
"vendor-1",
|
||||
str(uuid.uuid4()),
|
||||
compute_project,
|
||||
manager,
|
||||
"vendor:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_UNIX_SOCKET_NIO=1\nGNS3_UNIX_SOCKET_DIR=/var/run/socks",
|
||||
)
|
||||
_mock_wiring(vm)
|
||||
wiring_dir = _wiring_dir(vm)
|
||||
os.makedirs(wiring_dir, exist_ok=True)
|
||||
@@ -659,10 +693,19 @@ async def test_tap_wired_vendor_keeps_carrier_and_monitor(compute_project, manag
|
||||
behavior: the guards only apply to unix-socket NIO.
|
||||
"""
|
||||
|
||||
vm = VendorDockerVM("vendor-1", str(uuid.uuid4()), compute_project, manager, "vendor:latest",
|
||||
console_type="docker_exec", environment="GNS3_SKIP_INIT=1")
|
||||
with patch.object(DockerVM, "_set_adapter_carrier", new=AsyncioMagicMock()) as carrier, \
|
||||
patch.object(DockerVM, "_start_interface_monitor", new=AsyncioMagicMock()) as monitor:
|
||||
vm = VendorDockerVM(
|
||||
"vendor-1",
|
||||
str(uuid.uuid4()),
|
||||
compute_project,
|
||||
manager,
|
||||
"vendor:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1",
|
||||
)
|
||||
with (
|
||||
patch.object(DockerVM, "_set_adapter_carrier", new=AsyncioMagicMock()) as carrier,
|
||||
patch.object(DockerVM, "_start_interface_monitor", new=AsyncioMagicMock()) as monitor,
|
||||
):
|
||||
await vm._set_adapter_carrier(0, True)
|
||||
await vm._start_interface_monitor()
|
||||
# the base-class attribute is replaced by a plain mock (no descriptor
|
||||
|
||||
@@ -50,6 +50,7 @@ from gns3server.compute.docker.docker_error import DockerError, DockerHttp404Err
|
||||
# Helpers / fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _create_response(vm, entrypoint=None, volumes=None):
|
||||
"""Build the Docker /containers/create response (with image info merged)."""
|
||||
return {
|
||||
@@ -71,13 +72,18 @@ async def manager(port_manager):
|
||||
return m
|
||||
|
||||
|
||||
def _make_vm(compute_project, manager, environment=None, console_type="docker_exec",
|
||||
extra_volumes=None, adapters=4):
|
||||
def _make_vm(compute_project, manager, environment=None, console_type="docker_exec", extra_volumes=None, adapters=4):
|
||||
"""Build a VendorDockerVM with a fake cid (no create() called)."""
|
||||
vm = VendorDockerVM(
|
||||
"srlinux-1", str(uuid.uuid4()), compute_project, manager, "srlinux:latest",
|
||||
console_type=console_type, environment=environment,
|
||||
extra_volumes=extra_volumes or [], adapters=adapters,
|
||||
"srlinux-1",
|
||||
str(uuid.uuid4()),
|
||||
compute_project,
|
||||
manager,
|
||||
"srlinux:latest",
|
||||
console_type=console_type,
|
||||
environment=environment,
|
||||
extra_volumes=extra_volumes or [],
|
||||
adapters=adapters,
|
||||
)
|
||||
vm._cid = "e90e34656842"
|
||||
# Interface monitoring belongs to DockerVM and is covered by its focused
|
||||
@@ -91,6 +97,7 @@ def _make_vm(compute_project, manager, environment=None, console_type="docker_ex
|
||||
# Factory selection
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_factory_selects_vendor_when_docker_exec(manager):
|
||||
|
||||
assert manager._select_node_class(console_type="docker_exec") is VendorDockerVM
|
||||
@@ -123,12 +130,10 @@ async def test_create_node_sets_node_class(manager, compute_project, monkeypatch
|
||||
fake_super_create_node,
|
||||
)
|
||||
|
||||
await manager.create_node("v", compute_project.id, str(uuid.uuid4()),
|
||||
"srlinux:latest", console_type="docker_exec")
|
||||
await manager.create_node("v", compute_project.id, str(uuid.uuid4()), "srlinux:latest", console_type="docker_exec")
|
||||
assert captured["cls"] is VendorDockerVM
|
||||
|
||||
await manager.create_node("v", compute_project.id, str(uuid.uuid4()),
|
||||
"ubuntu:latest", console_type="telnet")
|
||||
await manager.create_node("v", compute_project.id, str(uuid.uuid4()), "ubuntu:latest", console_type="telnet")
|
||||
assert captured["cls"] is DockerVM
|
||||
|
||||
|
||||
@@ -136,6 +141,7 @@ async def test_create_node_sets_node_class(manager, compute_project, monkeypatch
|
||||
# GNS3_* env parsing
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_env_skip_init_true(compute_project, manager):
|
||||
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_SKIP_INIT=1")
|
||||
@@ -150,24 +156,23 @@ def test_env_skip_init_absent_defaults_true(compute_project, manager):
|
||||
|
||||
def test_env_interface_names(compute_project, manager):
|
||||
|
||||
vm = _make_vm(compute_project, manager,
|
||||
environment="GNS3_INTERFACE_NAMES=mgmt0,e1-1,e1-2,e1-3")
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_INTERFACE_NAMES=mgmt0,e1-1,e1-2,e1-3")
|
||||
assert vm._interface_names == ["mgmt0", "e1-1", "e1-2", "e1-3"]
|
||||
|
||||
|
||||
def test_env_console_cmd(compute_project, manager):
|
||||
|
||||
vm = _make_vm(compute_project, manager,
|
||||
environment="GNS3_CONSOLE_CMD=/opt/srlinux/bin/sr_cli")
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_CONSOLE_CMD=/opt/srlinux/bin/sr_cli")
|
||||
assert vm._console_cmd == "/opt/srlinux/bin/sr_cli"
|
||||
|
||||
|
||||
def test_env_multiple_lines(compute_project, manager):
|
||||
|
||||
vm = _make_vm(compute_project, manager,
|
||||
environment=("GNS3_SKIP_INIT=1\n"
|
||||
"GNS3_INTERFACE_NAMES=mgmt0,e1-1\n"
|
||||
"GNS3_CONSOLE_CMD=/opt/srlinux/bin/sr_cli\n"))
|
||||
vm = _make_vm(
|
||||
compute_project,
|
||||
manager,
|
||||
environment=("GNS3_SKIP_INIT=1\nGNS3_INTERFACE_NAMES=mgmt0,e1-1\nGNS3_CONSOLE_CMD=/opt/srlinux/bin/sr_cli\n"),
|
||||
)
|
||||
assert vm._gns3_init is False
|
||||
assert vm._interface_names == ["mgmt0", "e1-1"]
|
||||
assert vm._console_cmd == "/opt/srlinux/bin/sr_cli"
|
||||
@@ -183,18 +188,22 @@ def test_env_console_cmd_default_none(compute_project, manager):
|
||||
# create() — init.sh skip, GNS3_MAX_ETHERNET, /etc/network drop
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_skip_init_omits_init_sh(compute_project, manager):
|
||||
|
||||
response = _create_response(None, entrypoint=["/init"])
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images",
|
||||
return_value=[{"image": "srlinux"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query",
|
||||
return_value=response) as mock:
|
||||
vm = VendorDockerVM("srlinux-1", str(uuid.uuid4()), compute_project,
|
||||
manager, "srlinux:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1")
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "srlinux"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
|
||||
vm = VendorDockerVM(
|
||||
"srlinux-1",
|
||||
str(uuid.uuid4()),
|
||||
compute_project,
|
||||
manager,
|
||||
"srlinux:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1",
|
||||
)
|
||||
await vm.create()
|
||||
# the Entrypoint must NOT contain /gns3/init.sh
|
||||
sent = mock.call_args.kwargs["data"]
|
||||
@@ -206,13 +215,11 @@ async def test_create_skip_init_omits_init_sh(compute_project, manager):
|
||||
async def test_create_without_skip_init_prepends_init_sh(compute_project, manager):
|
||||
|
||||
response = _create_response(None, entrypoint=["/init"])
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images",
|
||||
return_value=[{"image": "srlinux"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query",
|
||||
return_value=response) as mock:
|
||||
vm = VendorDockerVM("srlinux-1", str(uuid.uuid4()), compute_project,
|
||||
manager, "srlinux:latest",
|
||||
console_type="docker_exec")
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "srlinux"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
|
||||
vm = VendorDockerVM(
|
||||
"srlinux-1", str(uuid.uuid4()), compute_project, manager, "srlinux:latest", console_type="docker_exec"
|
||||
)
|
||||
await vm.create()
|
||||
sent = mock.call_args.kwargs["data"]
|
||||
# init.sh IS prepended when not skipping
|
||||
@@ -223,14 +230,18 @@ async def test_create_without_skip_init_prepends_init_sh(compute_project, manage
|
||||
async def test_create_interface_names_sets_max_ethernet(compute_project, manager):
|
||||
|
||||
response = _create_response(None)
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images",
|
||||
return_value=[{"image": "srlinux"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query",
|
||||
return_value=response) as mock:
|
||||
vm = VendorDockerVM("srlinux-1", str(uuid.uuid4()), compute_project,
|
||||
manager, "srlinux:latest", adapters=4,
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_INTERFACE_NAMES=mgmt0,e1-1,e1-2,e1-3")
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "srlinux"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
|
||||
vm = VendorDockerVM(
|
||||
"srlinux-1",
|
||||
str(uuid.uuid4()),
|
||||
compute_project,
|
||||
manager,
|
||||
"srlinux:latest",
|
||||
adapters=4,
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_INTERFACE_NAMES=mgmt0,e1-1,e1-2,e1-3",
|
||||
)
|
||||
await vm.create()
|
||||
sent = mock.call_args.kwargs["data"]
|
||||
# last interface (adapter index 3) should be e1-3, not eth3
|
||||
@@ -244,17 +255,19 @@ async def test_create_drops_etc_network_for_skip_init(compute_project, manager):
|
||||
seed_proc = MagicMock()
|
||||
seed_proc.communicate = AsyncioMagicMock(return_value=(b"seedcid", b""))
|
||||
seed_proc.returncode = 0
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images",
|
||||
return_value=[{"image": "srlinux"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query",
|
||||
return_value=response) as mock:
|
||||
with patch("asyncio.subprocess.create_subprocess_exec",
|
||||
return_value=seed_proc):
|
||||
vm = VendorDockerVM("srlinux-1", str(uuid.uuid4()), compute_project,
|
||||
manager, "srlinux:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1",
|
||||
extra_volumes=["/etc/opt/srlinux"])
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "srlinux"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
|
||||
with patch("asyncio.subprocess.create_subprocess_exec", return_value=seed_proc):
|
||||
vm = VendorDockerVM(
|
||||
"srlinux-1",
|
||||
str(uuid.uuid4()),
|
||||
compute_project,
|
||||
manager,
|
||||
"srlinux:latest",
|
||||
console_type="docker_exec",
|
||||
environment="GNS3_SKIP_INIT=1",
|
||||
extra_volumes=["/etc/opt/srlinux"],
|
||||
)
|
||||
await vm.create()
|
||||
sent = mock.call_args.kwargs["data"]
|
||||
targets = [m["Target"] for m in sent["HostConfig"]["Mounts"]]
|
||||
@@ -277,13 +290,11 @@ async def test_create_drops_etc_network_for_skip_init(compute_project, manager):
|
||||
async def test_create_keeps_etc_network_without_skip_init(compute_project, manager):
|
||||
|
||||
response = _create_response(None)
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images",
|
||||
return_value=[{"image": "srlinux"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query",
|
||||
return_value=response) as mock:
|
||||
vm = VendorDockerVM("srlinux-1", str(uuid.uuid4()), compute_project,
|
||||
manager, "srlinux:latest",
|
||||
console_type="docker_exec")
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "srlinux"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
|
||||
vm = VendorDockerVM(
|
||||
"srlinux-1", str(uuid.uuid4()), compute_project, manager, "srlinux:latest", console_type="docker_exec"
|
||||
)
|
||||
await vm.create()
|
||||
sent = mock.call_args.kwargs["data"]
|
||||
targets = [m["Target"] for m in sent["HostConfig"]["Mounts"]]
|
||||
@@ -294,11 +305,11 @@ async def test_create_keeps_etc_network_without_skip_init(compute_project, manag
|
||||
# Interface renaming (_get_container_ifname / move_to_ns)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_move_to_ns_uses_renamed_interface(compute_project, manager):
|
||||
|
||||
vm = _make_vm(compute_project, manager,
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_INTERFACE_NAMES=mgmt0,e1-1,e1-2,e1-3")
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_SKIP_INIT=1\nGNS3_INTERFACE_NAMES=mgmt0,e1-1,e1-2,e1-3")
|
||||
vm._ubridge_hypervisor = MagicMock()
|
||||
vm._namespace = 42
|
||||
nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4343, "rhost": "127.0.0.1"})
|
||||
@@ -325,6 +336,7 @@ async def test_move_to_ns_falls_back_to_eth(compute_project, manager):
|
||||
# start() — docker_exec console dispatch + volume bridge + permission fix
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_docker_exec_dispatches_console(compute_project, manager):
|
||||
|
||||
@@ -373,6 +385,7 @@ async def test_start_without_skip_init_skips_vendor_passes(compute_project, mana
|
||||
# _fix_permissions — container-side, skips dead containers, targets volume paths
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fix_permissions_skips_dead_container(compute_project, manager):
|
||||
|
||||
@@ -411,8 +424,7 @@ async def test_fix_permissions_targets_volume_paths(compute_project, manager):
|
||||
proc.stderr = MagicMock()
|
||||
proc.stderr.read = AsyncioMagicMock(return_value=b"")
|
||||
|
||||
with patch("asyncio.subprocess.create_subprocess_exec",
|
||||
return_value=proc) as mock_exec:
|
||||
with patch("asyncio.subprocess.create_subprocess_exec", return_value=proc) as mock_exec:
|
||||
await vm._fix_permissions()
|
||||
# one exec per volume
|
||||
assert mock_exec.call_count == 2
|
||||
@@ -422,13 +434,14 @@ async def test_fix_permissions_targets_volume_paths(compute_project, manager):
|
||||
script = call_obj.args[-1] # last positional arg is the sh -c script
|
||||
assert "/gns3volumes" not in script
|
||||
assert '"/etc/opt/srlinux"' in script or '"/var/log/srlinux"' in script
|
||||
assert 'chown' in script
|
||||
assert "chown" in script
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# _prepare_volumes — host-side seeding (docker create + cp + rm)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _seed_proc(stdout=b"seedcid\n", returncode=0):
|
||||
proc = MagicMock()
|
||||
proc.communicate = AsyncioMagicMock(return_value=(stdout, b""))
|
||||
@@ -439,12 +452,10 @@ def _seed_proc(stdout=b"seedcid\n", returncode=0):
|
||||
@pytest.mark.asyncio
|
||||
async def test_prepare_volumes_seeds_unmarked_volume(compute_project, manager):
|
||||
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_SKIP_INIT=1",
|
||||
extra_volumes=["/etc/opt/srlinux"])
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_SKIP_INIT=1", extra_volumes=["/etc/opt/srlinux"])
|
||||
image_info = {"Config": {"Volumes": {}}}
|
||||
|
||||
with patch("asyncio.subprocess.create_subprocess_exec",
|
||||
return_value=_seed_proc()) as mock_exec:
|
||||
with patch("asyncio.subprocess.create_subprocess_exec", return_value=_seed_proc()) as mock_exec:
|
||||
await vm._prepare_volumes(image_info)
|
||||
# docker create + docker cp + docker rm
|
||||
assert mock_exec.call_count == 3
|
||||
@@ -465,8 +476,7 @@ async def test_prepare_volumes_never_overwrites_marked_volume(compute_project, m
|
||||
"""Regression guard: a volume that ever started (marker present) holds the
|
||||
node's saved configuration — re-seeding would reset it to factory."""
|
||||
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_SKIP_INIT=1",
|
||||
extra_volumes=["/etc/opt/srlinux"])
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_SKIP_INIT=1", extra_volumes=["/etc/opt/srlinux"])
|
||||
host_dir = os.path.join(vm.working_dir, "etc", "opt", "srlinux")
|
||||
os.makedirs(host_dir, exist_ok=True)
|
||||
marker = os.path.join(host_dir, ".gns3_perms")
|
||||
@@ -475,8 +485,7 @@ async def test_prepare_volumes_never_overwrites_marked_volume(compute_project, m
|
||||
with open(saved, "w") as f:
|
||||
f.write('{"user": "config"}')
|
||||
|
||||
with patch("asyncio.subprocess.create_subprocess_exec",
|
||||
return_value=_seed_proc()) as mock_exec:
|
||||
with patch("asyncio.subprocess.create_subprocess_exec", return_value=_seed_proc()) as mock_exec:
|
||||
await vm._prepare_volumes({"Config": {"Volumes": {}}})
|
||||
mock_exec.assert_not_called()
|
||||
with open(saved) as f:
|
||||
@@ -488,8 +497,7 @@ async def test_prepare_volumes_tolerates_missing_image_path(compute_project, man
|
||||
"""A volume path the image does not contain (e.g. XRd's /xr-storage-shadow)
|
||||
starts empty — cp fails, the marker is still written, no raise."""
|
||||
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_SKIP_INIT=1",
|
||||
extra_volumes=["/xr-storage-shadow"])
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_SKIP_INIT=1", extra_volumes=["/xr-storage-shadow"])
|
||||
calls = {"n": 0}
|
||||
|
||||
def proc_factory(*args, **kwargs):
|
||||
@@ -500,8 +508,7 @@ async def test_prepare_volumes_tolerates_missing_image_path(compute_project, man
|
||||
calls["n"] += 1
|
||||
return proc
|
||||
|
||||
with patch("asyncio.subprocess.create_subprocess_exec",
|
||||
side_effect=proc_factory):
|
||||
with patch("asyncio.subprocess.create_subprocess_exec", side_effect=proc_factory):
|
||||
await vm._prepare_volumes({"Config": {"Volumes": {}}})
|
||||
assert calls["n"] == 3 # rm still ran (finally path)
|
||||
host_dir = os.path.join(vm.working_dir, "xr-storage-shadow")
|
||||
@@ -512,8 +519,7 @@ async def test_prepare_volumes_tolerates_missing_image_path(compute_project, man
|
||||
async def test_prepare_volumes_skips_without_skip_init(compute_project, manager):
|
||||
|
||||
vm = _make_vm(compute_project, manager) # no SKIP_INIT
|
||||
with patch("asyncio.subprocess.create_subprocess_exec",
|
||||
return_value=_seed_proc()) as mock_exec:
|
||||
with patch("asyncio.subprocess.create_subprocess_exec", return_value=_seed_proc()) as mock_exec:
|
||||
await vm._prepare_volumes({"Config": {"Volumes": {"/etc/opt/srlinux": None}}})
|
||||
mock_exec.assert_not_called()
|
||||
|
||||
@@ -523,8 +529,7 @@ async def test_prepare_volumes_raises_when_seed_container_fails(compute_project,
|
||||
"""If `docker create` itself fails, creation must abort loudly instead of
|
||||
binding an empty directory over the NOS's config path."""
|
||||
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_SKIP_INIT=1",
|
||||
extra_volumes=["/etc/opt/srlinux"])
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_SKIP_INIT=1", extra_volumes=["/etc/opt/srlinux"])
|
||||
proc = _seed_proc(stdout=b"", returncode=1)
|
||||
|
||||
with patch("asyncio.subprocess.create_subprocess_exec", return_value=proc):
|
||||
@@ -536,6 +541,7 @@ async def test_prepare_volumes_raises_when_seed_container_fails(compute_project,
|
||||
# _cleanup_console_resources
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_cleanup_console_resources_closes_writer(compute_project, manager):
|
||||
|
||||
vm = _make_vm(compute_project, manager)
|
||||
@@ -558,11 +564,15 @@ def test_cleanup_console_resources_no_writer(compute_project, manager):
|
||||
# _LazyExecTelnetServer — upstream aliveness + reconnect/recreate logic
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _make_lazy_server(compute_project, manager, environment="GNS3_CONSOLE_CMD=/opt/srlinux/bin/sr_cli"):
|
||||
"""Build a _LazyExecTelnetServer with _create_exec mocked out (no docker)."""
|
||||
vm = _make_vm(compute_project, manager, environment=environment)
|
||||
srv = _LazyExecTelnetServer(
|
||||
vm, manager, "e90e34656842", "/opt/srlinux/bin/sr_cli",
|
||||
vm,
|
||||
manager,
|
||||
"e90e34656842",
|
||||
"/opt/srlinux/bin/sr_cli",
|
||||
allow_resize=vm._console_resize,
|
||||
)
|
||||
srv._create_exec = AsyncioMagicMock()
|
||||
@@ -655,7 +665,8 @@ async def test_client_naws_ignored_when_resize_disabled(compute_project, manager
|
||||
geometry (paging CLIs need the tall default for concurrent netmiko)."""
|
||||
|
||||
srv = _make_lazy_server(
|
||||
compute_project, manager,
|
||||
compute_project,
|
||||
manager,
|
||||
environment="GNS3_CONSOLE_RESIZE=0",
|
||||
)
|
||||
assert srv._allow_resize is False
|
||||
@@ -784,6 +795,7 @@ async def test_create_exec_cmd_has_no_while_true(compute_project, manager):
|
||||
# Container termination (graceful stop for vendor NOS)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_terminate_container_graceful_stop(compute_project, manager):
|
||||
"""With graceful=True (explicit user stop) vendor containers are SIGTERMed
|
||||
@@ -797,8 +809,7 @@ async def test_terminate_container_graceful_stop(compute_project, manager):
|
||||
|
||||
await vm._terminate_container(graceful=True)
|
||||
|
||||
manager.http_query.assert_called_once_with(
|
||||
"POST", "containers/e90e34656842/stop", params={"t": 60}, timeout=90)
|
||||
manager.http_query.assert_called_once_with("POST", "containers/e90e34656842/stop", params={"t": 60}, timeout=90)
|
||||
manager.query.assert_not_called() # no kill on the graceful path
|
||||
|
||||
|
||||
@@ -826,8 +837,7 @@ async def test_terminate_container_already_stopped_is_silent(compute_project, ma
|
||||
from gns3server.compute.docker.docker_error import DockerHttp304Error
|
||||
|
||||
vm = _make_vm(compute_project, manager)
|
||||
manager.http_query = AsyncioMagicMock(
|
||||
side_effect=DockerHttp304Error("Docker has returned an error: 304"))
|
||||
manager.http_query = AsyncioMagicMock(side_effect=DockerHttp304Error("Docker has returned an error: 304"))
|
||||
await vm._terminate_container(graceful=True) # must not raise
|
||||
|
||||
|
||||
@@ -840,13 +850,9 @@ async def test_stop_uses_graceful_termination(compute_project, manager):
|
||||
vm = _make_vm(compute_project, manager)
|
||||
with patch.object(DockerVM, "_clean_servers", new=AsyncioMagicMock()):
|
||||
with patch.object(DockerVM, "_stop_ubridge", new=AsyncioMagicMock()):
|
||||
with patch.object(
|
||||
DockerVM, "_get_container_state", new=AsyncioMagicMock(return_value="running")
|
||||
):
|
||||
with patch.object(DockerVM, "_get_container_state", new=AsyncioMagicMock(return_value="running")):
|
||||
vm._permissions_fixed = True
|
||||
with patch.object(
|
||||
VendorDockerVM, "_terminate_container", new=AsyncioMagicMock()
|
||||
) as mock_term:
|
||||
with patch.object(VendorDockerVM, "_terminate_container", new=AsyncioMagicMock()) as mock_term:
|
||||
await vm.stop()
|
||||
mock_term.assert_called_once_with(graceful=False)
|
||||
|
||||
@@ -880,8 +886,7 @@ async def test_terminate_container_uses_env_timeout(compute_project, manager):
|
||||
|
||||
await vm._terminate_container(graceful=True)
|
||||
|
||||
manager.http_query.assert_called_once_with(
|
||||
"POST", "containers/e90e34656842/stop", params={"t": 120}, timeout=150)
|
||||
manager.http_query.assert_called_once_with("POST", "containers/e90e34656842/stop", params={"t": 120}, timeout=150)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -890,13 +895,11 @@ async def test_create_reparse_refreshes_env_knobs(compute_project, manager):
|
||||
not on the next project reload: create() re-parses the vendor knobs."""
|
||||
|
||||
response = _create_response(None, entrypoint=["/init"])
|
||||
vm = _make_vm(compute_project, manager,
|
||||
environment="GNS3_SKIP_INIT=1\nGNS3_STOP_TIMEOUT=120")
|
||||
vm = _make_vm(compute_project, manager, environment="GNS3_SKIP_INIT=1\nGNS3_STOP_TIMEOUT=120")
|
||||
assert vm._gns3_init is False and vm._stop_timeout == 120
|
||||
|
||||
vm._environment = "GNS3_STOP_TIMEOUT=5" # knob removed + value changed
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images",
|
||||
return_value=[{"image": "srlinux"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "srlinux"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response):
|
||||
await vm.create()
|
||||
|
||||
|
||||
@@ -104,30 +104,20 @@ async def test_duplicate_node(manager, compute_project):
|
||||
Duplicate dynamips do nothing it's manage outside the
|
||||
filesystem
|
||||
"""
|
||||
with asyncio_patch('gns3server.compute.dynamips.nodes.c7200.C7200.create'):
|
||||
source_node = await manager.create_node(
|
||||
'R1',
|
||||
compute_project.id,
|
||||
str(uuid.uuid4()),
|
||||
platform="c7200"
|
||||
)
|
||||
destination_node = await manager.create_node(
|
||||
'R2',
|
||||
compute_project.id,
|
||||
str(uuid.uuid4()),
|
||||
platform="c7200"
|
||||
)
|
||||
with asyncio_patch("gns3server.compute.dynamips.nodes.c7200.C7200.create"):
|
||||
source_node = await manager.create_node("R1", compute_project.id, str(uuid.uuid4()), platform="c7200")
|
||||
destination_node = await manager.create_node("R2", compute_project.id, str(uuid.uuid4()), platform="c7200")
|
||||
destination_node._hypervisor = AsyncioMagicMock()
|
||||
|
||||
with open(os.path.join(source_node.working_dir, 'c3600_i1_nvram'), 'w+') as f:
|
||||
with open(os.path.join(source_node.working_dir, "c3600_i1_nvram"), "w+") as f:
|
||||
f.write("1")
|
||||
with open(source_node.startup_config_path, 'w+') as f:
|
||||
f.write('hostname R1\necho TEST')
|
||||
with open(source_node.startup_config_path, "w+") as f:
|
||||
f.write("hostname R1\necho TEST")
|
||||
await manager.duplicate_node(source_node.id, destination_node.id)
|
||||
assert not os.path.exists(os.path.join(destination_node.working_dir, 'c3600_i1_nvram'))
|
||||
assert not os.path.exists(os.path.join(destination_node.working_dir, "c3600_i1_nvram"))
|
||||
with open(destination_node.startup_config_path) as f:
|
||||
content = f.read()
|
||||
assert content == '!\nhostname R2\necho TEST'
|
||||
assert content == "!\nhostname R2\necho TEST"
|
||||
with pytest.raises(DynamipsError):
|
||||
source_node.status = "started"
|
||||
await manager.duplicate_node(source_node.id, destination_node.id)
|
||||
@@ -28,10 +28,10 @@ def test_mac_command():
|
||||
node.nios[0].name = "Ethernet0"
|
||||
node.nios[1] = NIOUDP(55, "127.0.0.1", 56)
|
||||
node.nios[1].name = "Ethernet1"
|
||||
#node._hypervisor.send = AsyncioMagicMock(return_value=["0050.7966.6801 1 Ethernet0", "0050.7966.6802 1 Ethernet1"])
|
||||
#console = EthernetSwitchConsole(node)
|
||||
#assert async_run(console.mac()) == \
|
||||
# node._hypervisor.send = AsyncioMagicMock(return_value=["0050.7966.6801 1 Ethernet0", "0050.7966.6802 1 Ethernet1"])
|
||||
# console = EthernetSwitchConsole(node)
|
||||
# assert async_run(console.mac()) == \
|
||||
# "Port Mac VLAN\n" \
|
||||
# "Ethernet0 00:50:79:66:68:01 1\n" \
|
||||
# "Ethernet1 00:50:79:66:68:02 1\n"
|
||||
#node._hypervisor.send.assert_called_with("ethsw show_mac_addr_table Test")
|
||||
# node._hypervisor.send.assert_called_with("ethsw show_mac_addr_table Test")
|
||||
@@ -67,7 +67,7 @@ def fake_iou_bin(images_dir):
|
||||
|
||||
path = os.path.join(images_dir, "iou.bin")
|
||||
with open(path, "w+") as f:
|
||||
f.write('\x7fELF\x01\x01\x01')
|
||||
f.write("\x7fELF\x01\x01\x01")
|
||||
os.chmod(path, stat.S_IREAD | stat.S_IEXEC)
|
||||
return path
|
||||
|
||||
@@ -103,7 +103,7 @@ async def test_start(vm):
|
||||
mock_process.communicate = AsyncioMagicMock(return_value=(None, None))
|
||||
await vm.start()
|
||||
assert vm.is_running()
|
||||
assert vm.command_line == ' '.join(mock_exec.call_args[0])
|
||||
assert vm.command_line == " ".join(mock_exec.call_args[0])
|
||||
|
||||
assert vm._check_requirements.called
|
||||
assert vm._check_iou_license.called
|
||||
@@ -183,10 +183,10 @@ async def test_rename_nvram_file(vm):
|
||||
It should rename the nvram file to the correct name before launching the VM
|
||||
"""
|
||||
|
||||
with open(os.path.join(vm.working_dir, "nvram_0000{}".format(vm.application_id + 1)), 'w+') as f:
|
||||
with open(os.path.join(vm.working_dir, "nvram_0000{}".format(vm.application_id + 1)), "w+") as f:
|
||||
f.write("1")
|
||||
|
||||
with open(os.path.join(vm.working_dir, "vlan.dat-0000{}".format(vm.application_id + 1)), 'w+') as f:
|
||||
with open(os.path.join(vm.working_dir, "vlan.dat-0000{}".format(vm.application_id + 1)), "w+") as f:
|
||||
f.write("1")
|
||||
|
||||
vm._rename_nvram_file()
|
||||
@@ -455,14 +455,18 @@ async def test_build_command(vm):
|
||||
|
||||
def test_get_startup_config(vm):
|
||||
|
||||
content = "service timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption"
|
||||
content = (
|
||||
"service timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption"
|
||||
)
|
||||
vm.startup_config = content
|
||||
assert vm.startup_config == content
|
||||
|
||||
|
||||
def test_update_startup_config(vm):
|
||||
|
||||
content = "service timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption"
|
||||
content = (
|
||||
"service timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption"
|
||||
)
|
||||
vm.startup_config_content = content
|
||||
filepath = os.path.join(vm.working_dir, "startup-config.cfg")
|
||||
assert os.path.exists(filepath)
|
||||
@@ -472,7 +476,9 @@ def test_update_startup_config(vm):
|
||||
|
||||
def test_update_startup_config_empty(vm):
|
||||
|
||||
content = "service timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption"
|
||||
content = (
|
||||
"service timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption"
|
||||
)
|
||||
vm.startup_config_content = content
|
||||
filepath = os.path.join(vm.working_dir, "startup-config.cfg")
|
||||
assert os.path.exists(filepath)
|
||||
@@ -496,7 +502,7 @@ def test_change_name(vm):
|
||||
|
||||
path = os.path.join(vm.working_dir, "startup-config.cfg")
|
||||
vm.name = "world"
|
||||
with open(path, 'w+') as f:
|
||||
with open(path, "w+") as f:
|
||||
f.write("hostname world")
|
||||
vm.name = "hello"
|
||||
assert vm.name == "hello"
|
||||
@@ -504,7 +510,7 @@ def test_change_name(vm):
|
||||
assert f.read() == "hostname hello"
|
||||
# support hostname not sync
|
||||
vm.name = "alpha"
|
||||
with open(path, 'w+') as f:
|
||||
with open(path, "w+") as f:
|
||||
f.write("no service password-encryption\nhostname beta\nno ip icmp rate-limit unreachable")
|
||||
vm.name = "charlie"
|
||||
assert vm.name == "charlie"
|
||||
@@ -526,13 +532,18 @@ async def test_library_check(vm):
|
||||
@pytest.mark.asyncio
|
||||
async def test_enable_l1_keepalives(vm):
|
||||
|
||||
with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="***************************************************************\n\n-l Enable Layer 1 keepalive messages\n-u <n> UDP port base for distributed networks\n"):
|
||||
with asyncio_patch(
|
||||
"gns3server.utils.asyncio.subprocess_check_output",
|
||||
return_value="***************************************************************\n\n-l Enable Layer 1 keepalive messages\n-u <n> UDP port base for distributed networks\n",
|
||||
):
|
||||
command = ["test"]
|
||||
await vm._enable_l1_keepalives(command)
|
||||
assert command == ["test", "-l"]
|
||||
|
||||
with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="***************************************************************\n\n-u <n> UDP port base for distributed networks\n"):
|
||||
|
||||
with asyncio_patch(
|
||||
"gns3server.utils.asyncio.subprocess_check_output",
|
||||
return_value="***************************************************************\n\n-u <n> UDP port base for distributed networks\n",
|
||||
):
|
||||
command = ["test"]
|
||||
with pytest.raises(IOUError):
|
||||
await vm._enable_l1_keepalives(command)
|
||||
@@ -543,7 +554,9 @@ async def test_enable_l1_keepalives(vm):
|
||||
async def test_start_capture(vm, tmpdir, manager, free_console_port):
|
||||
|
||||
output_file = str(tmpdir / "test.pcap")
|
||||
nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"})
|
||||
nio = manager.create_nio(
|
||||
{"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"}
|
||||
)
|
||||
await vm.adapter_add_nio_binding(0, 0, nio)
|
||||
await vm.start_capture(0, 0, output_file)
|
||||
assert vm._adapters[0].get_nio(0).capturing
|
||||
@@ -553,7 +566,9 @@ async def test_start_capture(vm, tmpdir, manager, free_console_port):
|
||||
async def test_stop_capture(vm, tmpdir, manager, free_console_port):
|
||||
|
||||
output_file = str(tmpdir / "test.pcap")
|
||||
nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"})
|
||||
nio = manager.create_nio(
|
||||
{"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"}
|
||||
)
|
||||
await vm.adapter_add_nio_binding(0, 0, nio)
|
||||
await vm.start_capture(0, 0, output_file)
|
||||
assert vm._adapters[0].get_nio(0).capturing
|
||||
|
||||
@@ -26,8 +26,8 @@ from gns3server.compute.marker.marker_listener import MarkerListener
|
||||
# Registry
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestMarkerRegistry:
|
||||
|
||||
class TestMarkerRegistry:
|
||||
def test_register_and_lookup(self):
|
||||
MarkerManager.reset()
|
||||
mgr = MarkerManager.instance()
|
||||
@@ -85,6 +85,7 @@ class TestMarkerRegistry:
|
||||
# MarkerListener parsing
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class FakeMarkerManager:
|
||||
def __init__(self):
|
||||
self.events = []
|
||||
@@ -100,13 +101,10 @@ class FakeMarkerManager:
|
||||
self.events.append((project_id, event))
|
||||
|
||||
def register(self, project_id, node_id, filter_name, link_id, tag):
|
||||
self._entries[(node_id, filter_name)] = {
|
||||
"project_id": project_id, "link_id": link_id, "tag": tag
|
||||
}
|
||||
self._entries[(node_id, filter_name)] = {"project_id": project_id, "link_id": link_id, "tag": tag}
|
||||
|
||||
|
||||
class TestMarkerListener:
|
||||
|
||||
def test_parses_valid_mark_datagram(self):
|
||||
fmgr = FakeMarkerManager()
|
||||
fmgr.register("p1", "n1", "f1", "l1", tag=7)
|
||||
@@ -193,9 +191,7 @@ class TestMarkerListener:
|
||||
fmgr.register("p", "n", "f", "registry-link", tag=1)
|
||||
lis = MarkerListener(fmgr)
|
||||
lis.connection_made(None)
|
||||
lis.datagram_received(
|
||||
b"MARK 3.0 node=n filter=f link=signal-link tag=1 len=42\n", None
|
||||
)
|
||||
lis.datagram_received(b"MARK 3.0 node=n filter=f link=signal-link tag=1 len=42\n", None)
|
||||
assert fmgr.events[0][1]["link_id"] == "signal-link"
|
||||
|
||||
def test_link_dash_falls_back_to_registry_link(self):
|
||||
@@ -249,9 +245,9 @@ class TestMarkerListener:
|
||||
# UDP round-trip
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestMarkerManagerUDP:
|
||||
|
||||
async def test_listener_receives_and_dispatches(self):
|
||||
MarkerManager.reset()
|
||||
mgr = MarkerManager.instance()
|
||||
@@ -273,12 +269,8 @@ class TestMarkerManagerUDP:
|
||||
self.transport = transport
|
||||
|
||||
sp = SendProto()
|
||||
transport, _ = await loop.create_datagram_endpoint(
|
||||
lambda: sp, remote_addr=("127.0.0.1", mgr.port)
|
||||
)
|
||||
transport.sendto(
|
||||
b"MARK 123.456 node=node-rt filter=filt-rt tag=10 len=88\n"
|
||||
)
|
||||
transport, _ = await loop.create_datagram_endpoint(lambda: sp, remote_addr=("127.0.0.1", mgr.port))
|
||||
transport.sendto(b"MARK 123.456 node=node-rt filter=filt-rt tag=10 len=88\n")
|
||||
await asyncio.sleep(0.15)
|
||||
transport.close()
|
||||
|
||||
|
||||
@@ -28,10 +28,7 @@ def qemu_img():
|
||||
We can't use shutil.which because for safety reason we break
|
||||
the PATH to avoid test interacting with real binaries
|
||||
"""
|
||||
paths = [
|
||||
"/usr/bin/qemu-img",
|
||||
"/usr/local/bin/qemu-img"
|
||||
]
|
||||
paths = ["/usr/bin/qemu-img", "/usr/local/bin/qemu-img"]
|
||||
for path in paths:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
@@ -60,9 +57,9 @@ def test_invalid_file():
|
||||
|
||||
def test_invalid_empty_file(tmpdir):
|
||||
|
||||
open(str(tmpdir / 'a'), 'w+').close()
|
||||
open(str(tmpdir / "a"), "w+").close()
|
||||
with pytest.raises(Qcow2Error):
|
||||
Qcow2(str(tmpdir / 'a'))
|
||||
Qcow2(str(tmpdir / "a"))
|
||||
|
||||
|
||||
@pytest.mark.skipif(qemu_img() is None, reason="qemu-img is not available")
|
||||
|
||||
@@ -44,7 +44,10 @@ def fake_qemu_img_binary(tmpdir):
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_qemu_version():
|
||||
|
||||
with asyncio_patch("gns3server.compute.qemu.subprocess_check_output", return_value="QEMU emulator version 2.2.0, Copyright (c) 2003-2008 Fabrice Bellard"):
|
||||
with asyncio_patch(
|
||||
"gns3server.compute.qemu.subprocess_check_output",
|
||||
return_value="QEMU emulator version 2.2.0, Copyright (c) 2003-2008 Fabrice Bellard",
|
||||
):
|
||||
version = await Qemu.get_qemu_version("/tmp/qemu-test")
|
||||
assert version == "2.2.0"
|
||||
|
||||
@@ -61,7 +64,10 @@ async def test_binary_list(monkeypatch, tmpdir):
|
||||
f.write("1")
|
||||
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
||||
|
||||
with asyncio_patch("gns3server.compute.qemu.subprocess_check_output", return_value="QEMU emulator version 2.2.0, Copyright (c) 2003-2008 Fabrice Bellard") as mock:
|
||||
with asyncio_patch(
|
||||
"gns3server.compute.qemu.subprocess_check_output",
|
||||
return_value="QEMU emulator version 2.2.0, Copyright (c) 2003-2008 Fabrice Bellard",
|
||||
) as mock:
|
||||
version = "2.2.0"
|
||||
|
||||
qemus = await Qemu.binary_list()
|
||||
@@ -121,8 +127,8 @@ async def test_get_kvm_archs_kvm_ok():
|
||||
|
||||
with patch("os.path.exists", return_value=True):
|
||||
archs = await Qemu.get_kvm_archs()
|
||||
if platform.machine() == 'x86_64':
|
||||
assert archs == ['x86_64', 'i386']
|
||||
if platform.machine() == "x86_64":
|
||||
assert archs == ["x86_64", "i386"]
|
||||
else:
|
||||
assert archs == [platform.machine()]
|
||||
|
||||
|
||||
@@ -102,21 +102,28 @@ async def test_vm(compute_project, manager, fake_qemu_binary):
|
||||
async def test_vm_create(compute_project, manager, fake_qemu_binary):
|
||||
|
||||
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, qemu_path=fake_qemu_binary)
|
||||
fake_img = os.path.join(vm.working_dir, 'hello')
|
||||
with open(fake_img, 'w+') as f:
|
||||
f.write('hello')
|
||||
fake_img = os.path.join(vm.working_dir, "hello")
|
||||
with open(fake_img, "w+") as f:
|
||||
f.write("hello")
|
||||
vm._hda_disk_image = fake_img
|
||||
|
||||
await vm.create()
|
||||
|
||||
# tests if `create` created md5sums
|
||||
assert os.path.exists(os.path.join(vm.working_dir, 'hello.md5sum'))
|
||||
assert os.path.exists(os.path.join(vm.working_dir, "hello.md5sum"))
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_vm_invalid_qemu_with_platform(compute_project, manager, fake_qemu_binary):
|
||||
|
||||
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, qemu_path="/usr/fake/bin/qemu-system-64", platform="x86_64")
|
||||
vm = QemuVM(
|
||||
"test",
|
||||
"00010203-0405-0607-0809-0a0b0c0d0e0f",
|
||||
compute_project,
|
||||
manager,
|
||||
qemu_path="/usr/fake/bin/qemu-system-64",
|
||||
platform="x86_64",
|
||||
)
|
||||
|
||||
assert vm.qemu_path == fake_qemu_binary
|
||||
assert vm.platform == "x86_64"
|
||||
@@ -125,7 +132,13 @@ async def test_vm_invalid_qemu_with_platform(compute_project, manager, fake_qemu
|
||||
@pytest.mark.asyncio
|
||||
async def test_vm_invalid_qemu_without_platform(compute_project, manager, fake_qemu_binary):
|
||||
|
||||
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, qemu_path="/usr/fake/bin/qemu-system-x86_64")
|
||||
vm = QemuVM(
|
||||
"test",
|
||||
"00010203-0405-0607-0809-0a0b0c0d0e0f",
|
||||
compute_project,
|
||||
manager,
|
||||
qemu_path="/usr/fake/bin/qemu-system-x86_64",
|
||||
)
|
||||
|
||||
assert vm.qemu_path == fake_qemu_binary
|
||||
assert vm.platform == "x86_64"
|
||||
@@ -149,7 +162,7 @@ async def test_start(vm, running_subprocess_mock):
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=running_subprocess_mock) as mock:
|
||||
await vm.start()
|
||||
assert vm.is_running()
|
||||
assert vm.command_line == ' '.join(mock.call_args[0])
|
||||
assert vm.command_line == " ".join(mock.call_args[0])
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -232,7 +245,9 @@ async def test_suspend(vm, running_subprocess_mock):
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_nio_binding_udp(vm):
|
||||
|
||||
nio = Qemu.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
|
||||
nio = Qemu.instance().create_nio(
|
||||
{"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}}
|
||||
)
|
||||
assert nio.lport == 4242
|
||||
await vm.adapter_add_nio_binding(0, nio)
|
||||
assert nio.lport == 4242
|
||||
@@ -241,7 +256,9 @@ async def test_add_nio_binding_udp(vm):
|
||||
@pytest.mark.asyncio
|
||||
async def test_port_remove_nio_binding(vm):
|
||||
|
||||
nio = Qemu.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
|
||||
nio = Qemu.instance().create_nio(
|
||||
{"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}}
|
||||
)
|
||||
await vm.adapter_add_nio_binding(0, nio)
|
||||
await vm.adapter_remove_nio_binding(0)
|
||||
assert vm._ethernet_adapters[0].ports[0] is None
|
||||
@@ -271,9 +288,9 @@ def test_set_qemu_path(vm, tmpdir, fake_qemu_binary):
|
||||
vm.qemu_path = None
|
||||
|
||||
# Should not crash with unicode characters
|
||||
path = str(tmpdir / "\u62FF" / "qemu-system-mips")
|
||||
path = str(tmpdir / "\u62ff" / "qemu-system-mips")
|
||||
|
||||
os.makedirs(str(tmpdir / "\u62FF"))
|
||||
os.makedirs(str(tmpdir / "\u62ff"))
|
||||
|
||||
# Raise because file doesn't exists
|
||||
with pytest.raises(QemuError):
|
||||
@@ -360,17 +377,38 @@ async def test_disk_options(vm, tmpdir, fake_qemu_img_binary):
|
||||
open(vm._hda_disk_image, "w+").close()
|
||||
open(vm._hdb_disk_image, "w+").close()
|
||||
|
||||
with (asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM._find_disk_file_format", return_value="qcow2")):
|
||||
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM._find_disk_file_format", return_value="qcow2"):
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
|
||||
options = await vm._disk_options()
|
||||
assert process.called
|
||||
args, kwargs = process.call_args
|
||||
assert args == (fake_qemu_img_binary, "create", "-o", "backing_file={}".format(vm._hda_disk_image), "-F", "qcow2", "-f", "qcow2", os.path.join(vm.working_dir, "hda_disk.qcow2")) or \
|
||||
args == (fake_qemu_img_binary, "create", "-o", "backing_file={}".format(vm._hdb_disk_image), "-F", "qcow2", "-f", "qcow2", os.path.join(vm.working_dir, "hdb_disk.qcow2"))
|
||||
assert args == (
|
||||
fake_qemu_img_binary,
|
||||
"create",
|
||||
"-o",
|
||||
"backing_file={}".format(vm._hda_disk_image),
|
||||
"-F",
|
||||
"qcow2",
|
||||
"-f",
|
||||
"qcow2",
|
||||
os.path.join(vm.working_dir, "hda_disk.qcow2"),
|
||||
) or args == (
|
||||
fake_qemu_img_binary,
|
||||
"create",
|
||||
"-o",
|
||||
"backing_file={}".format(vm._hdb_disk_image),
|
||||
"-F",
|
||||
"qcow2",
|
||||
"-f",
|
||||
"qcow2",
|
||||
os.path.join(vm.working_dir, "hdb_disk.qcow2"),
|
||||
)
|
||||
|
||||
assert options == [
|
||||
'-drive', 'file=' + os.path.join(vm.working_dir, "hda_disk.qcow2") + ',if=ide,index=0,media=disk,id=drive0',
|
||||
'-drive', 'file=' + os.path.join(vm.working_dir, "hdb_disk.qcow2") + ',if=none,index=1,media=disk,id=drive1',
|
||||
"-drive",
|
||||
"file=" + os.path.join(vm.working_dir, "hda_disk.qcow2") + ",if=ide,index=0,media=disk,id=drive0",
|
||||
"-drive",
|
||||
"file=" + os.path.join(vm.working_dir, "hdb_disk.qcow2") + ",if=none,index=1,media=disk,id=drive1",
|
||||
]
|
||||
|
||||
|
||||
@@ -382,7 +420,7 @@ async def test_cdrom_option(vm, tmpdir, fake_qemu_img_binary):
|
||||
|
||||
options = await vm._build_command()
|
||||
|
||||
assert ' '.join(['-cdrom', str(tmpdir / "test.iso")]) in ' '.join(options)
|
||||
assert " ".join(["-cdrom", str(tmpdir / "test.iso")]) in " ".join(options)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -391,7 +429,7 @@ async def test_bios_option(vm, tmpdir, fake_qemu_img_binary):
|
||||
vm._bios_image = str(tmpdir / "test.img")
|
||||
open(vm._bios_image, "w+").close()
|
||||
options = await vm._build_command()
|
||||
assert ' '.join(['-bios', str(tmpdir / "test.img")]) in ' '.join(options)
|
||||
assert " ".join(["-bios", str(tmpdir / "test.img")]) in " ".join(options)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Test not working on Windows")
|
||||
@@ -407,14 +445,16 @@ async def test_uefi_boot_mode_option(vm, tmpdir, images_dir, fake_qemu_img_binar
|
||||
else:
|
||||
ovmf_code_path = os.path.join(images_dir, "OVMF_CODE_4M.fd")
|
||||
with open(ovmf_code_path, "w+") as f:
|
||||
f.write('1')
|
||||
f.write("1")
|
||||
ovmf_vars_path = os.path.join(images_dir, "OVMF_VARS_4M.fd")
|
||||
with open(ovmf_vars_path, "w+") as f:
|
||||
f.write('1')
|
||||
f.write("1")
|
||||
|
||||
options = await vm._build_command()
|
||||
assert ' '.join(["-drive", "if=pflash,format=raw,readonly,file={}".format(ovmf_code_path)]) in ' '.join(options)
|
||||
assert ' '.join(["-drive", "if=pflash,format=raw,file={}".format(os.path.join(vm.working_dir, "OVMF_VARS_4M.fd"))]) in ' '.join(options)
|
||||
assert " ".join(["-drive", "if=pflash,format=raw,readonly,file={}".format(ovmf_code_path)]) in " ".join(options)
|
||||
assert " ".join(
|
||||
["-drive", "if=pflash,format=raw,file={}".format(os.path.join(vm.working_dir, "OVMF_VARS_4M.fd"))]
|
||||
) in " ".join(options)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -429,20 +469,20 @@ async def test_uefi_with_bios_image_already_configured(vm, tmpdir, fake_qemu_img
|
||||
@pytest.mark.asyncio
|
||||
async def test_vnc_option(vm, fake_qemu_img_binary):
|
||||
|
||||
vm._console_type = 'vnc'
|
||||
vm._console_type = "vnc"
|
||||
vm._console = 5905
|
||||
options = await vm._build_command()
|
||||
assert '-vnc 127.0.0.1:5' in ' '.join(options)
|
||||
assert "-vnc 127.0.0.1:5" in " ".join(options)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_spice_option(vm, fake_qemu_img_binary):
|
||||
|
||||
vm._console_type = 'spice'
|
||||
vm._console_type = "spice"
|
||||
vm._console = 5905
|
||||
options = await vm._build_command()
|
||||
assert '-spice addr=127.0.0.1,port=5905,disable-ticketing' in ' '.join(options)
|
||||
assert '-vga qxl' in ' '.join(options)
|
||||
assert "-spice addr=127.0.0.1,port=5905,disable-ticketing" in " ".join(options)
|
||||
assert "-vga qxl" in " ".join(options)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -452,9 +492,10 @@ async def test_tpm_option(vm, tmpdir, fake_qemu_img_binary):
|
||||
tpm_sock = os.path.join(vm.temporary_directory, "swtpm.sock")
|
||||
with patch("os.path.exists", return_value=True) as os_path:
|
||||
options = await vm._build_command()
|
||||
assert '-chardev socket,id=chrtpm,path={}'.format(tpm_sock) in ' '.join(options)
|
||||
assert '-tpmdev emulator,id=tpm0,chardev=chrtpm' in ' '.join(options)
|
||||
assert '-device tpm-tis,tpmdev=tpm0' in ' '.join(options)
|
||||
assert "-chardev socket,id=chrtpm,path={}".format(tpm_sock) in " ".join(options)
|
||||
assert "-tpmdev emulator,id=tpm0,chardev=chrtpm" in " ".join(options)
|
||||
assert "-device tpm-tis,tpmdev=tpm0" in " ".join(options)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_disk_options_multiple_disk(vm, tmpdir, fake_qemu_img_binary):
|
||||
@@ -477,10 +518,14 @@ async def test_disk_options_multiple_disk(vm, tmpdir, fake_qemu_img_binary):
|
||||
options = await vm._disk_options()
|
||||
|
||||
assert options == [
|
||||
'-drive', 'file=' + os.path.join(vm.working_dir, "hda_disk.qcow2") + ',if=ide,index=0,media=disk,id=drive0',
|
||||
'-drive', 'file=' + os.path.join(vm.working_dir, "hdb_disk.qcow2") + ',if=ide,index=1,media=disk,id=drive1',
|
||||
'-drive', 'file=' + os.path.join(vm.working_dir, "hdc_disk.qcow2") + ',if=ide,index=2,media=disk,id=drive2',
|
||||
'-drive', 'file=' + os.path.join(vm.working_dir, "hdd_disk.qcow2") + ',if=ide,index=3,media=disk,id=drive3'
|
||||
"-drive",
|
||||
"file=" + os.path.join(vm.working_dir, "hda_disk.qcow2") + ",if=ide,index=0,media=disk,id=drive0",
|
||||
"-drive",
|
||||
"file=" + os.path.join(vm.working_dir, "hdb_disk.qcow2") + ",if=ide,index=1,media=disk,id=drive1",
|
||||
"-drive",
|
||||
"file=" + os.path.join(vm.working_dir, "hdc_disk.qcow2") + ",if=ide,index=2,media=disk,id=drive2",
|
||||
"-drive",
|
||||
"file=" + os.path.join(vm.working_dir, "hdd_disk.qcow2") + ",if=ide,index=3,media=disk,id=drive3",
|
||||
]
|
||||
|
||||
|
||||
@@ -534,7 +579,6 @@ async def test_control_vm_expect_text(vm, running_subprocess_mock):
|
||||
reader = MagicMock()
|
||||
writer = MagicMock()
|
||||
with asyncio_patch("asyncio.open_connection", return_value=(reader, writer)):
|
||||
|
||||
future = asyncio.Future()
|
||||
future.set_result(b"epic product")
|
||||
reader.readline.return_value = future
|
||||
@@ -578,7 +622,7 @@ async def test_build_command(vm, fake_qemu_binary):
|
||||
"-netdev",
|
||||
"socket,id=gns3-0,udp=127.0.0.1:{},localaddr=127.0.0.1:{}".format(nio.rport, nio.lport),
|
||||
"-display",
|
||||
"none"
|
||||
"none",
|
||||
]
|
||||
|
||||
|
||||
@@ -648,7 +692,7 @@ async def test_build_command_kvm_2_4(linux_platform, vm, fake_qemu_binary):
|
||||
"e1000,mac={},bus=pci-bridge1,addr=0x00,netdev=gns3-0".format(vm._mac_address),
|
||||
"-netdev",
|
||||
"socket,id=gns3-0,udp=127.0.0.1:{},localaddr=127.0.0.1:{}".format(nio.rport, nio.lport),
|
||||
"-nographic"
|
||||
"-nographic",
|
||||
]
|
||||
|
||||
|
||||
@@ -697,10 +741,12 @@ async def test_build_command_two_adapters(vm, fake_qemu_binary):
|
||||
"-netdev",
|
||||
"socket,id=gns3-0,udp=127.0.0.1:{},localaddr=127.0.0.1:{}".format(nio1.rport, nio1.lport),
|
||||
"-device",
|
||||
"e1000,mac={},bus=pci-bridge1,addr=0x01,netdev=gns3-1".format(int_to_macaddress(macaddress_to_int(vm._mac_address) + 1)),
|
||||
"e1000,mac={},bus=pci-bridge1,addr=0x01,netdev=gns3-1".format(
|
||||
int_to_macaddress(macaddress_to_int(vm._mac_address) + 1)
|
||||
),
|
||||
"-netdev",
|
||||
"socket,id=gns3-1,udp=127.0.0.1:{},localaddr=127.0.0.1:{}".format(nio2.rport, nio2.lport),
|
||||
"-nographic"
|
||||
"-nographic",
|
||||
]
|
||||
|
||||
|
||||
@@ -725,7 +771,6 @@ async def test_build_command_two_adapters_mac_address(vm):
|
||||
mac_1 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 1)
|
||||
assert mac_0[:8] == "00:42:ab"
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
|
||||
|
||||
cmd = await vm._build_command()
|
||||
assert "e1000,mac={},bus=pci-bridge1,addr=0x00,netdev=gns3-0".format(mac_0) in cmd
|
||||
assert "e1000,mac={},bus=pci-bridge1,addr=0x01,netdev=gns3-1".format(mac_1) in cmd
|
||||
@@ -747,7 +792,7 @@ async def test_build_command_large_number_of_adapters(vm):
|
||||
cmd = await vm._build_command()
|
||||
|
||||
# Count if we have 100 e1000 adapters in the command
|
||||
assert len([l for l in cmd if "e1000" in l ]) == 100
|
||||
assert len([l for l in cmd if "e1000" in l]) == 100
|
||||
assert len(vm._ethernet_adapters) == 100
|
||||
|
||||
assert "e1000,mac={},bus=pci-bridge1,addr=0x00,netdev=gns3-0".format(mac_0) in cmd
|
||||
|
||||
@@ -113,7 +113,9 @@ def test_aux(compute_project, manager, port_manager):
|
||||
aux = port_manager.get_free_tcp_port(compute_project)
|
||||
port_manager.release_tcp_port(aux, compute_project)
|
||||
|
||||
node = DockerVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "ubuntu", aux=aux, aux_type="telnet")
|
||||
node = DockerVM(
|
||||
"test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "ubuntu", aux=aux, aux_type="telnet"
|
||||
)
|
||||
assert node.aux == aux
|
||||
node.aux = None
|
||||
assert node.aux is None
|
||||
@@ -125,13 +127,17 @@ def test_allocate_aux(compute_project, manager):
|
||||
assert node.aux is None
|
||||
|
||||
# Docker has an aux port by default
|
||||
node = DockerVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "ubuntu", aux_type="telnet")
|
||||
node = DockerVM(
|
||||
"test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "ubuntu", aux_type="telnet"
|
||||
)
|
||||
assert node.aux is not None
|
||||
|
||||
|
||||
def test_change_aux_port(compute_project, manager, port_manager):
|
||||
|
||||
node = DockerVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "ubuntu", aux_type="telnet")
|
||||
node = DockerVM(
|
||||
"test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "ubuntu", aux_type="telnet"
|
||||
)
|
||||
port1 = port_manager.get_free_tcp_port(node.project)
|
||||
port2 = port_manager.get_free_tcp_port(node.project)
|
||||
port_manager.release_tcp_port(port1, node.project)
|
||||
@@ -145,25 +151,20 @@ def test_change_aux_port(compute_project, manager, port_manager):
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_ubridge_udp_connection(node):
|
||||
|
||||
filters = {
|
||||
"latency": [10]
|
||||
}
|
||||
filters = {"latency": [10]}
|
||||
|
||||
snio = NIOUDP(1245, "localhost", 1246)
|
||||
dnio = NIOUDP(1245, "localhost", 1244)
|
||||
dnio.filters = filters
|
||||
with asyncio_patch("gns3server.compute.base_node.BaseNode._ubridge_apply_filters") as mock:
|
||||
await node.update_ubridge_udp_connection('VPCS-10', snio, dnio)
|
||||
await node.update_ubridge_udp_connection("VPCS-10", snio, dnio)
|
||||
mock.assert_called_with("VPCS-10", filters)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ubridge_apply_filters(node):
|
||||
|
||||
filters = OrderedDict((
|
||||
('latency', [10]),
|
||||
('bpf', ["icmp[icmptype] == 8\ntcp src port 53"])
|
||||
))
|
||||
filters = OrderedDict((("latency", [10]), ("bpf", ["icmp[icmptype] == 8\ntcp src port 53"])))
|
||||
node._ubridge_send = AsyncioMagicMock()
|
||||
await node._ubridge_apply_filters("VPCS-10", filters)
|
||||
node._ubridge_send.assert_any_call("bridge reset_packet_filters VPCS-10")
|
||||
@@ -173,14 +174,12 @@ async def test_ubridge_apply_filters(node):
|
||||
@pytest.mark.asyncio
|
||||
async def test_ubridge_apply_bpf_filters(node):
|
||||
|
||||
filters = {
|
||||
"bpf": ["icmp[icmptype] == 8\ntcp src port 53"]
|
||||
}
|
||||
filters = {"bpf": ["icmp[icmptype] == 8\ntcp src port 53"]}
|
||||
node._ubridge_send = AsyncioMagicMock()
|
||||
await node._ubridge_apply_filters("VPCS-10", filters)
|
||||
node._ubridge_send.assert_any_call("bridge reset_packet_filters VPCS-10")
|
||||
node._ubridge_send.assert_any_call("bridge add_packet_filter VPCS-10 filter0 bpf \"icmp[icmptype] == 8\"")
|
||||
node._ubridge_send.assert_any_call("bridge add_packet_filter VPCS-10 filter1 bpf \"tcp src port 53\"")
|
||||
node._ubridge_send.assert_any_call('bridge add_packet_filter VPCS-10 filter0 bpf "icmp[icmptype] == 8"')
|
||||
node._ubridge_send.assert_any_call('bridge add_packet_filter VPCS-10 filter1 bpf "tcp src port 53"')
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -259,8 +258,16 @@ async def test_apply_markers_appends_linktype_for_serial(compute_project, manage
|
||||
node = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
|
||||
node._ubridge_send = AsyncioMagicMock()
|
||||
nio = NIOUDP(1234, "127.0.0.1", 4321)
|
||||
nio.markers = {"m": {"bpf": "icmp", "tag": None, "link_id": "L1",
|
||||
"direction": None, "data_link_type": "DLT_C_HDLC", "enabled": True}}
|
||||
nio.markers = {
|
||||
"m": {
|
||||
"bpf": "icmp",
|
||||
"tag": None,
|
||||
"link_id": "L1",
|
||||
"direction": None,
|
||||
"data_link_type": "DLT_C_HDLC",
|
||||
"enabled": True,
|
||||
}
|
||||
}
|
||||
with patch("gns3server.compute.marker.marker_manager.MarkerManager") as mm:
|
||||
mm.instance.return_value.register = MagicMock()
|
||||
await node._ubridge_apply_markers("VPCS-10", nio)
|
||||
@@ -274,8 +281,16 @@ async def test_apply_markers_omits_linktype_for_ethernet(compute_project, manage
|
||||
node = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
|
||||
node._ubridge_send = AsyncioMagicMock()
|
||||
nio = NIOUDP(1234, "127.0.0.1", 4321)
|
||||
nio.markers = {"m": {"bpf": "icmp", "tag": None, "link_id": "L1",
|
||||
"direction": None, "data_link_type": "DLT_EN10MB", "enabled": True}}
|
||||
nio.markers = {
|
||||
"m": {
|
||||
"bpf": "icmp",
|
||||
"tag": None,
|
||||
"link_id": "L1",
|
||||
"direction": None,
|
||||
"data_link_type": "DLT_EN10MB",
|
||||
"enabled": True,
|
||||
}
|
||||
}
|
||||
with patch("gns3server.compute.marker.marker_manager.MarkerManager") as mm:
|
||||
mm.instance.return_value.register = MagicMock()
|
||||
await node._ubridge_apply_markers("VPCS-10", nio)
|
||||
@@ -334,8 +349,7 @@ async def test_delete_marker_capture_drops_from_nio_markers(compute_project, man
|
||||
# nio.markers and starting the node reinstalls it (empty pcap reappears).
|
||||
node = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
|
||||
nio = NIOUDP(1234, "127.0.0.1", 4321)
|
||||
nio.markers = {"m": {"bpf": "icmp", "tag": None, "link_id": "L1",
|
||||
"direction": None, "enabled": True}}
|
||||
nio.markers = {"m": {"bpf": "icmp", "tag": None, "link_id": "L1", "direction": None, "enabled": True}}
|
||||
await node.delete_marker_capture("m", "L1", nio)
|
||||
assert "m" not in nio.markers
|
||||
|
||||
@@ -404,16 +418,20 @@ async def test_apply_markers_rebuilds_changed_bpf(compute_project, manager):
|
||||
node._ubridge_hypervisor = MagicMock()
|
||||
node._ubridge_hypervisor.is_running.return_value = True
|
||||
node._marker_filter_bridges["m", "L1"] = "VPCS-10"
|
||||
node._marker_specs["m", "L1"] = {"bpf": "icmp", "tag": None, "direction": None,
|
||||
"data_link_type": None, "enabled": True}
|
||||
node._marker_specs["m", "L1"] = {
|
||||
"bpf": "icmp",
|
||||
"tag": None,
|
||||
"direction": None,
|
||||
"data_link_type": None,
|
||||
"enabled": True,
|
||||
}
|
||||
nio = NIOUDP(1234, "127.0.0.1", 4321)
|
||||
nio.markers = {"m": {"bpf": "tcp", "tag": None, "link_id": "L1",
|
||||
"direction": None, "enabled": True}}
|
||||
nio.markers = {"m": {"bpf": "tcp", "tag": None, "link_id": "L1", "direction": None, "enabled": True}}
|
||||
with patch("gns3server.compute.marker.marker_manager.MarkerManager") as mm:
|
||||
mm.instance.return_value.register = MagicMock()
|
||||
await node._ubridge_apply_markers("VPCS-10", nio)
|
||||
cmds = [c.args[0] for c in node._ubridge_send.call_args_list]
|
||||
assert any("delete_packet_filter VPCS-10 m" in c for c in cmds) # old removed
|
||||
assert any("delete_packet_filter VPCS-10 m" in c for c in cmds) # old removed
|
||||
assert any("add_packet_filter VPCS-10 m mark" in c and "tcp" in c for c in cmds) # new added
|
||||
|
||||
|
||||
@@ -441,10 +459,10 @@ async def test_apply_markers_preserves_markers_on_other_bridges(compute_project,
|
||||
mm.instance.return_value.unregister = MagicMock()
|
||||
await node._ubridge_apply_markers("VPCS-10", nio)
|
||||
cmds = [c.args[0] for c in node._ubridge_send.call_args_list]
|
||||
assert any("delete_packet_filter VPCS-10 m" in c for c in cmds) # L1 removed on its bridge
|
||||
assert not any("VPCS-20" in c for c in cmds) # other bridge untouched
|
||||
assert any("delete_packet_filter VPCS-10 m" in c for c in cmds) # L1 removed on its bridge
|
||||
assert not any("VPCS-20" in c for c in cmds) # other bridge untouched
|
||||
assert ("m", "L1") not in node._marker_filter_bridges
|
||||
assert ("m", "L2") in node._marker_filter_bridges # L2 preserved
|
||||
assert ("m", "L2") in node._marker_filter_bridges # L2 preserved
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -467,6 +485,7 @@ class _GoneConsoleWebsocket:
|
||||
|
||||
def __init__(self):
|
||||
from types import SimpleNamespace
|
||||
|
||||
self.client = SimpleNamespace(host="127.0.0.1", port=5000)
|
||||
|
||||
async def receive(self):
|
||||
@@ -474,12 +493,14 @@ class _GoneConsoleWebsocket:
|
||||
|
||||
async def send_bytes(self, data):
|
||||
from starlette.websockets import WebSocketDisconnect
|
||||
|
||||
raise WebSocketDisconnect(code=1006)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_console_websocket_client_disconnect_while_node_output_streams(
|
||||
compute_project, manager, port_manager, monkeypatch, caplog):
|
||||
compute_project, manager, port_manager, monkeypatch, caplog
|
||||
):
|
||||
# regression test: the client disconnects while the node is still streaming
|
||||
# console output. telnet_forward used to let the (empty-str) WebSocketDisconnect
|
||||
# from send_bytes escape, logging a message-less WARNING.
|
||||
@@ -505,10 +526,7 @@ async def test_console_websocket_client_disconnect_while_node_output_streams(
|
||||
|
||||
assert telnet_writer.close.called
|
||||
assert not [r for r in caplog.records if r.levelno >= logging.WARNING]
|
||||
assert any(
|
||||
"has disconnected from compute console WebSocket while node output" in r.message
|
||||
for r in caplog.records
|
||||
)
|
||||
assert any("has disconnected from compute console WebSocket while node output" in r.message for r in caplog.records)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -81,10 +81,10 @@ def test_get_abs_image_path(qemu, tmpdir, config):
|
||||
|
||||
os.makedirs(str(tmpdir / "QEMU"))
|
||||
path1 = force_unix_path(str(tmpdir / "test1.bin"))
|
||||
open(path1, 'w+').close()
|
||||
open(path1, "w+").close()
|
||||
|
||||
path2 = force_unix_path(str(tmpdir / "QEMU" / "test2.bin"))
|
||||
open(path2, 'w+').close()
|
||||
open(path2, "w+").close()
|
||||
|
||||
config.settings.Server.images_path = str(tmpdir)
|
||||
assert qemu.get_abs_image_path(path1) == path1
|
||||
@@ -180,21 +180,21 @@ def test_get_relative_image_path(qemu, tmpdir, config):
|
||||
os.makedirs(str(tmpdir / "images1" / "QEMU"))
|
||||
os.makedirs(str(tmpdir / "images1" / "VBOX"))
|
||||
path1 = force_unix_path(str(tmpdir / "images1" / "test1.bin"))
|
||||
open(path1, 'w+').close()
|
||||
open(path1, "w+").close()
|
||||
|
||||
path2 = force_unix_path(str(tmpdir / "images1" / "QEMU" / "test2.bin"))
|
||||
open(path2, 'w+').close()
|
||||
open(path2, "w+").close()
|
||||
|
||||
os.makedirs(str(tmpdir / "images2"))
|
||||
path3 = force_unix_path(str(tmpdir / "images2" / "test3.bin"))
|
||||
open(path3, 'w+').close()
|
||||
open(path3, "w+").close()
|
||||
|
||||
path4 = force_unix_path(str(tmpdir / "test4.bin"))
|
||||
open(path4, 'w+').close()
|
||||
open(path4, "w+").close()
|
||||
|
||||
# The user use an image of another emulator we return the full path
|
||||
path5 = force_unix_path(str(tmpdir / "images1" / "VBOX" / "test5.bin"))
|
||||
open(path5, 'w+').close()
|
||||
open(path5, "w+").close()
|
||||
|
||||
config.settings.Server.images_path = str(tmpdir / "images1")
|
||||
config.settings.Server.additional_images_paths = str(tmpdir / "images2")
|
||||
@@ -221,9 +221,9 @@ async def test_list_images(qemu, tmpdir):
|
||||
f.write("1234567")
|
||||
|
||||
with patch("gns3server.utils.images.default_images_directory", return_value=str(tmp_images_dir)):
|
||||
assert sorted(await qemu.list_images(), key=lambda k: k['filename']) == [
|
||||
assert sorted(await qemu.list_images(), key=lambda k: k["filename"]) == [
|
||||
{"filename": "a.qcow2", "path": "a.qcow2", "md5sum": "fcea920f7412b5da7be0cf42b8c93759", "filesize": 7},
|
||||
{"filename": "b.qcow2", "path": "b.qcow2", "md5sum": "fcea920f7412b5da7be0cf42b8c93759", "filesize": 7}
|
||||
{"filename": "b.qcow2", "path": "b.qcow2", "md5sum": "fcea920f7412b5da7be0cf42b8c93759", "filesize": 7},
|
||||
]
|
||||
|
||||
|
||||
@@ -243,11 +243,15 @@ async def test_list_images_recursives(qemu, tmpdir):
|
||||
f.write("1234567")
|
||||
|
||||
with patch("gns3server.utils.images.default_images_directory", return_value=str(tmp_images_dir)):
|
||||
|
||||
assert sorted(await qemu.list_images(), key=lambda k: k['filename']) == [
|
||||
assert sorted(await qemu.list_images(), key=lambda k: k["filename"]) == [
|
||||
{"filename": "a.qcow2", "path": "a.qcow2", "md5sum": "fcea920f7412b5da7be0cf42b8c93759", "filesize": 7},
|
||||
{"filename": "b.qcow2", "path": "b.qcow2", "md5sum": "fcea920f7412b5da7be0cf42b8c93759", "filesize": 7},
|
||||
{"filename": "c.qcow2", "path": force_unix_path(os.path.sep.join(["c", "c.qcow2"])), "md5sum": "fcea920f7412b5da7be0cf42b8c93759", "filesize": 7}
|
||||
{
|
||||
"filename": "c.qcow2",
|
||||
"path": force_unix_path(os.path.sep.join(["c", "c.qcow2"])),
|
||||
"md5sum": "fcea920f7412b5da7be0cf42b8c93759",
|
||||
"filesize": 7,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -299,10 +303,10 @@ async def test_duplicate_vpcs(vpcs, compute_project):
|
||||
@pytest.mark.asyncio
|
||||
async def test_duplicate_ethernet_switch(compute_project):
|
||||
|
||||
with asyncio_patch('gns3server.compute.dynamips.nodes.ethernet_switch.EthernetSwitch.create'):
|
||||
with asyncio_patch("gns3server.compute.dynamips.nodes.ethernet_switch.EthernetSwitch.create"):
|
||||
dynamips_manager = Dynamips.instance()
|
||||
source_node_id = str(uuid.uuid4())
|
||||
await dynamips_manager.create_node("SW-1", compute_project.id, source_node_id, node_type='ethernet_switch')
|
||||
await dynamips_manager.create_node("SW-1", compute_project.id, source_node_id, node_type="ethernet_switch")
|
||||
destination_node_id = str(uuid.uuid4())
|
||||
await dynamips_manager.create_node("SW-2", compute_project.id, destination_node_id, node_type='ethernet_switch')
|
||||
await dynamips_manager.create_node("SW-2", compute_project.id, destination_node_id, node_type="ethernet_switch")
|
||||
await dynamips_manager.duplicate_node(source_node_id, destination_node_id)
|
||||
@@ -34,7 +34,7 @@ async def test_queue():
|
||||
|
||||
notifications.emit("test", {"a": 1})
|
||||
res = await queue.get(5)
|
||||
assert res == ('test', {"a": 1}, {})
|
||||
assert res == ("test", {"a": 1}, {})
|
||||
|
||||
assert len(notifications._listeners) == 0
|
||||
|
||||
|
||||
@@ -48,8 +48,8 @@ async def node(compute_project, manager):
|
||||
@pytest.mark.asyncio
|
||||
async def test_affect_uuid():
|
||||
|
||||
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f')
|
||||
assert p.id == '00010203-0405-0607-0809-0a0b0c0d0e0f'
|
||||
p = Project(project_id="00010203-0405-0607-0809-0a0b0c0d0e0f")
|
||||
assert p.id == "00010203-0405-0607-0809-0a0b0c0d0e0f"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -58,14 +58,14 @@ async def test_clean_tmp_directory():
|
||||
The tmp directory should be clean at project open and close
|
||||
"""
|
||||
|
||||
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f')
|
||||
p = Project(project_id="00010203-0405-0607-0809-0a0b0c0d0e0f")
|
||||
path = p.tmp_working_directory()
|
||||
os.makedirs(path)
|
||||
await p.close()
|
||||
assert not os.path.exists(path)
|
||||
|
||||
os.makedirs(path)
|
||||
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f')
|
||||
p = Project(project_id="00010203-0405-0607-0809-0a0b0c0d0e0f")
|
||||
assert not os.path.exists(path)
|
||||
|
||||
|
||||
@@ -99,11 +99,7 @@ async def test_variables():
|
||||
async def test_json():
|
||||
|
||||
p = Project(project_id=str(uuid4()))
|
||||
assert p.asdict() == {
|
||||
"name": p.name,
|
||||
"project_id": p.id,
|
||||
"variables": None
|
||||
}
|
||||
assert p.asdict() == {"name": p.name, "project_id": p.id, "variables": None}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -111,11 +107,7 @@ async def test_json_with_variables():
|
||||
|
||||
variables = [{"name": "VAR1", "value": "VAL1"}]
|
||||
p = Project(project_id=str(uuid4()), variables=variables)
|
||||
assert p.asdict() == {
|
||||
"name": p.name,
|
||||
"project_id": p.id,
|
||||
"variables": variables
|
||||
}
|
||||
assert p.asdict() == {"name": p.name, "project_id": p.id, "variables": variables}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -123,7 +115,7 @@ async def test_node_working_directory(node, projects_dir):
|
||||
|
||||
directory = projects_dir
|
||||
p = Project(project_id=str(uuid4()))
|
||||
assert p.node_working_directory(node) == os.path.join(directory, p.id, 'project-files', node.module_name, node.id)
|
||||
assert p.node_working_directory(node) == os.path.join(directory, p.id, "project-files", node.module_name, node.id)
|
||||
assert os.path.exists(p.node_working_directory(node))
|
||||
|
||||
|
||||
@@ -132,7 +124,7 @@ async def test_node_working_path(node, projects_dir):
|
||||
|
||||
directory = projects_dir
|
||||
p = Project(project_id=str(uuid4()))
|
||||
assert p.node_working_path(node) == os.path.join(directory, p.id, 'project-files', node.module_name, node.id)
|
||||
assert p.node_working_path(node) == os.path.join(directory, p.id, "project-files", node.module_name, node.id)
|
||||
# after this execution directory structure should not be created
|
||||
assert not os.path.exists(p.node_working_path(node))
|
||||
|
||||
@@ -193,14 +185,8 @@ async def test_list_files():
|
||||
files = await project.list_files()
|
||||
|
||||
assert files == [
|
||||
{
|
||||
"path": "test.txt",
|
||||
"md5sum": "ad0234829205b9033196ba818f7a872b"
|
||||
},
|
||||
{
|
||||
"path": os.path.join("vm-1", "dynamips", "test.bin"),
|
||||
"md5sum": "098f6bcd4621d373cade4e832627b4f6"
|
||||
}
|
||||
{"path": "test.txt", "md5sum": "ad0234829205b9033196ba818f7a872b"},
|
||||
{"path": os.path.join("vm-1", "dynamips", "test.bin"), "md5sum": "098f6bcd4621d373cade4e832627b4f6"},
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -24,12 +24,12 @@ from gns3server.compute.project_manager import ProjectManager
|
||||
def test_create_project():
|
||||
|
||||
pm = ProjectManager.instance()
|
||||
project = pm.create_project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f')
|
||||
assert project == pm.get_project('00010203-0405-0607-0809-0a0b0c0d0e0f')
|
||||
project = pm.create_project(project_id="00010203-0405-0607-0809-0a0b0c0d0e0f")
|
||||
assert project == pm.get_project("00010203-0405-0607-0809-0a0b0c0d0e0f")
|
||||
|
||||
|
||||
def test_project_not_found():
|
||||
|
||||
pm = ProjectManager.instance()
|
||||
with pytest.raises(ComputeNotFoundError):
|
||||
pm.get_project('00010203-0405-0607-0809-000000000000')
|
||||
pm.get_project("00010203-0405-0607-0809-000000000000")
|
||||
@@ -9,13 +9,15 @@ def test_compute_statistics_preserves_load_average_precision() -> None:
|
||||
swap = SimpleNamespace(total=1024, free=512, used=512, percent=50)
|
||||
disk = SimpleNamespace(total=16384, used=4096, free=12288, percent=25)
|
||||
|
||||
with patch("gns3server.api.routes.compute.compute.CpuPercent.get", return_value=10), \
|
||||
patch("gns3server.api.routes.compute.compute.get_cpu_model", return_value="Test CPU"), \
|
||||
patch("gns3server.api.routes.compute.compute.psutil.virtual_memory", return_value=memory), \
|
||||
patch("gns3server.api.routes.compute.compute.psutil.swap_memory", return_value=swap), \
|
||||
patch("gns3server.api.routes.compute.compute.psutil.disk_usage", return_value=disk), \
|
||||
patch("gns3server.api.routes.compute.compute.psutil.cpu_count", return_value=4), \
|
||||
patch("gns3server.api.routes.compute.compute.psutil.getloadavg", return_value=(1.25, 2.5, 3.75)):
|
||||
with (
|
||||
patch("gns3server.api.routes.compute.compute.CpuPercent.get", return_value=10),
|
||||
patch("gns3server.api.routes.compute.compute.get_cpu_model", return_value="Test CPU"),
|
||||
patch("gns3server.api.routes.compute.compute.psutil.virtual_memory", return_value=memory),
|
||||
patch("gns3server.api.routes.compute.compute.psutil.swap_memory", return_value=swap),
|
||||
patch("gns3server.api.routes.compute.compute.psutil.disk_usage", return_value=disk),
|
||||
patch("gns3server.api.routes.compute.compute.psutil.cpu_count", return_value=4),
|
||||
patch("gns3server.api.routes.compute.compute.psutil.getloadavg", return_value=(1.25, 2.5, 3.75)),
|
||||
):
|
||||
statistics = compute_statistics()
|
||||
|
||||
assert statistics["load_average"] == [1.25, 2.5, 3.75]
|
||||
|
||||
@@ -50,6 +50,7 @@ def _make(transport, tmp_path, monkeypatch, node_id="abc123", host="127.0.0.1"):
|
||||
# __init__: transport selection
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_init_unix_creates_socket_dir_and_path(tmp_path, monkeypatch):
|
||||
|
||||
hyp = _make("unix", tmp_path, monkeypatch, node_id="abc123")
|
||||
@@ -84,6 +85,7 @@ def test_init_tcp_sets_host_port(tmp_path, monkeypatch):
|
||||
# _build_command + endpoint
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_build_command_unix(tmp_path, monkeypatch):
|
||||
|
||||
hyp = _make("unix", tmp_path, monkeypatch)
|
||||
@@ -134,6 +136,7 @@ def test_endpoint_tcp(tmp_path, monkeypatch):
|
||||
# stop: AF_UNIX socket cleanup
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_stop_unlinks_unix_socket(tmp_path, monkeypatch):
|
||||
|
||||
@@ -163,6 +166,7 @@ async def test_stop_tcp_has_no_socket_to_unlink(tmp_path, monkeypatch):
|
||||
# version requirement
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_requires_ubridge_1_2_3(tmp_path, monkeypatch):
|
||||
|
||||
@@ -194,6 +198,7 @@ async def test_accepts_ubridge_1_2_3(tmp_path, monkeypatch):
|
||||
# start: fail-fast on an immediately-exiting uBridge
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_detects_immediate_exit(tmp_path, monkeypatch):
|
||||
# An unsupported flag (e.g. -U on an old ubridge) makes the process exit at
|
||||
@@ -203,8 +208,10 @@ async def test_start_detects_immediate_exit(tmp_path, monkeypatch):
|
||||
proc = MagicMock()
|
||||
proc.pid = 1234
|
||||
proc.returncode = 2 # already exited
|
||||
with patch.object(Hypervisor, "_check_ubridge_version", new_callable=AsyncMock), \
|
||||
patch("asyncio.create_subprocess_exec", new_callable=AsyncMock, return_value=proc):
|
||||
with (
|
||||
patch.object(Hypervisor, "_check_ubridge_version", new_callable=AsyncMock),
|
||||
patch("asyncio.create_subprocess_exec", new_callable=AsyncMock, return_value=proc),
|
||||
):
|
||||
with pytest.raises(UbridgeError, match="exited immediately"):
|
||||
await hyp.start()
|
||||
|
||||
@@ -216,7 +223,9 @@ async def test_start_proceeds_when_process_keeps_running(tmp_path, monkeypatch):
|
||||
proc = MagicMock()
|
||||
proc.pid = 1234
|
||||
proc.returncode = None # still running
|
||||
with patch.object(Hypervisor, "_check_ubridge_version", new_callable=AsyncMock), \
|
||||
patch("asyncio.create_subprocess_exec", new_callable=AsyncMock, return_value=proc):
|
||||
with (
|
||||
patch.object(Hypervisor, "_check_ubridge_version", new_callable=AsyncMock),
|
||||
patch("asyncio.create_subprocess_exec", new_callable=AsyncMock, return_value=proc),
|
||||
):
|
||||
await hyp.start() # must NOT raise
|
||||
assert hyp._process is proc
|
||||
@@ -76,12 +76,14 @@ def test_vboxmanage_path(manager, config, tmpdir):
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_vms(manager):
|
||||
|
||||
vm_list = ['"Windows 8.1" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}',
|
||||
'"Carriage',
|
||||
'Return" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c3f3}',
|
||||
'',
|
||||
'"<inaccessible>" {42b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}',
|
||||
'"Linux Microcore 4.7.1" {ccd8c50b-c172-457d-99fa-dd69371ede0e}']
|
||||
vm_list = [
|
||||
'"Windows 8.1" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}',
|
||||
'"Carriage',
|
||||
'Return" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c3f3}',
|
||||
"",
|
||||
'"<inaccessible>" {42b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}',
|
||||
'"Linux Microcore 4.7.1" {ccd8c50b-c172-457d-99fa-dd69371ede0e}',
|
||||
]
|
||||
|
||||
async def execute_mock(cmd, args):
|
||||
if cmd == "list":
|
||||
@@ -96,7 +98,4 @@ async def test_list_vms(manager):
|
||||
with asyncio_patch("gns3server.compute.virtualbox.VirtualBox.execute") as mock:
|
||||
mock.side_effect = execute_mock
|
||||
vms = await manager.list_vms()
|
||||
assert vms == [
|
||||
{"vmname": "Windows 8.1", "ram": 512},
|
||||
{"vmname": "Linux Microcore 4.7.1", "ram": 256}
|
||||
]
|
||||
assert vms == [{"vmname": "Windows 8.1", "ram": 512}, {"vmname": "Linux Microcore 4.7.1", "ram": 256}]
|
||||
@@ -99,7 +99,9 @@ async def test_vm_invalid_virtualbox_api_version(compute_project, manager):
|
||||
@pytest.mark.asyncio
|
||||
async def test_vm_adapter_add_nio_binding_adapter_not_exist(vm, manager, free_console_port):
|
||||
|
||||
nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"})
|
||||
nio = manager.create_nio(
|
||||
{"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"}
|
||||
)
|
||||
with pytest.raises(VirtualBoxError):
|
||||
await vm.adapter_add_nio_binding(15, nio)
|
||||
|
||||
|
||||
@@ -58,7 +58,9 @@ async def test_json(vm, tmpdir, compute_project):
|
||||
async def test_start_capture(vm, tmpdir, manager, free_console_port):
|
||||
|
||||
output_file = str(tmpdir / "test.pcap")
|
||||
nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"})
|
||||
nio = manager.create_nio(
|
||||
{"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"}
|
||||
)
|
||||
vm.adapters = 1
|
||||
await vm.adapter_add_nio_binding(0, nio)
|
||||
await vm.start_capture(0, output_file)
|
||||
@@ -69,7 +71,9 @@ async def test_start_capture(vm, tmpdir, manager, free_console_port):
|
||||
async def test_stop_capture(vm, tmpdir, manager, free_console_port):
|
||||
|
||||
output_file = str(tmpdir / "test.pcap")
|
||||
nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"})
|
||||
nio = manager.create_nio(
|
||||
{"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"}
|
||||
)
|
||||
vm.adapters = 1
|
||||
await vm.adapter_add_nio_binding(0, nio)
|
||||
await vm.start_capture(0, output_file)
|
||||
|
||||
@@ -60,7 +60,10 @@ async def test_vm(compute_project, manager):
|
||||
@pytest.mark.asyncio
|
||||
async def test_vm_check_vpcs_version(vm):
|
||||
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.subprocess_check_output", return_value="Welcome to Virtual PC Simulator, version 0.9"):
|
||||
with asyncio_patch(
|
||||
"gns3server.compute.vpcs.vpcs_vm.subprocess_check_output",
|
||||
return_value="Welcome to Virtual PC Simulator, version 0.9",
|
||||
):
|
||||
await vm._check_vpcs_version()
|
||||
assert vm._vpcs_version == parse_version("0.9")
|
||||
|
||||
@@ -68,7 +71,10 @@ async def test_vm_check_vpcs_version(vm):
|
||||
@pytest.mark.asyncio
|
||||
async def test_vm_check_vpcs_version_0_6_1(vm):
|
||||
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.subprocess_check_output", return_value="Welcome to Virtual PC Simulator, version 0.6.1"):
|
||||
with asyncio_patch(
|
||||
"gns3server.compute.vpcs.vpcs_vm.subprocess_check_output",
|
||||
return_value="Welcome to Virtual PC Simulator, version 0.6.1",
|
||||
):
|
||||
await vm._check_vpcs_version()
|
||||
assert vm._vpcs_version == parse_version("0.6.1")
|
||||
|
||||
@@ -76,9 +82,14 @@ async def test_vm_check_vpcs_version_0_6_1(vm):
|
||||
@pytest.mark.asyncio
|
||||
async def test_vm_invalid_vpcs_version(vm, manager):
|
||||
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.subprocess_check_output", return_value="Welcome to Virtual PC Simulator, version 0.1"):
|
||||
with asyncio_patch(
|
||||
"gns3server.compute.vpcs.vpcs_vm.subprocess_check_output",
|
||||
return_value="Welcome to Virtual PC Simulator, version 0.1",
|
||||
):
|
||||
with pytest.raises(VPCSError):
|
||||
nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
|
||||
nio = manager.create_nio(
|
||||
{"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}}
|
||||
)
|
||||
await vm.port_add_nio_binding(0, nio)
|
||||
await vm._check_vpcs_version()
|
||||
assert vm.name == "test"
|
||||
@@ -110,22 +121,25 @@ async def test_start(vm):
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec:
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
|
||||
await vm.start()
|
||||
assert mock_exec.call_args[0] == (vm._vpcs_path(),
|
||||
'-p',
|
||||
str(vm._internal_console_port),
|
||||
'-m', '1',
|
||||
'-i',
|
||||
'1',
|
||||
'-F',
|
||||
'-R',
|
||||
'-s',
|
||||
ANY,
|
||||
'-c',
|
||||
ANY,
|
||||
'-t',
|
||||
'127.0.0.1')
|
||||
assert mock_exec.call_args[0] == (
|
||||
vm._vpcs_path(),
|
||||
"-p",
|
||||
str(vm._internal_console_port),
|
||||
"-m",
|
||||
"1",
|
||||
"-i",
|
||||
"1",
|
||||
"-F",
|
||||
"-R",
|
||||
"-s",
|
||||
ANY,
|
||||
"-c",
|
||||
ANY,
|
||||
"-t",
|
||||
"127.0.0.1",
|
||||
)
|
||||
assert vm.is_running()
|
||||
assert vm.command_line == ' '.join(mock_exec.call_args[0])
|
||||
assert vm.command_line == " ".join(mock_exec.call_args[0])
|
||||
(action, event, kwargs) = await queue.get(1)
|
||||
assert action == "node.updated"
|
||||
assert event == vm
|
||||
@@ -145,22 +159,27 @@ async def test_start_0_6_1(vm):
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec:
|
||||
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
|
||||
nio = VPCS.instance().create_nio(
|
||||
{"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}}
|
||||
)
|
||||
await vm.port_add_nio_binding(0, nio)
|
||||
await vm.start()
|
||||
assert mock_exec.call_args[0] == (vm._vpcs_path(),
|
||||
'-p',
|
||||
str(vm._internal_console_port),
|
||||
'-m', '1',
|
||||
'-i',
|
||||
'1',
|
||||
'-F',
|
||||
'-s',
|
||||
ANY,
|
||||
'-c',
|
||||
ANY,
|
||||
'-t',
|
||||
'127.0.0.1')
|
||||
assert mock_exec.call_args[0] == (
|
||||
vm._vpcs_path(),
|
||||
"-p",
|
||||
str(vm._internal_console_port),
|
||||
"-m",
|
||||
"1",
|
||||
"-i",
|
||||
"1",
|
||||
"-F",
|
||||
"-s",
|
||||
ANY,
|
||||
"-c",
|
||||
ANY,
|
||||
"-t",
|
||||
"127.0.0.1",
|
||||
)
|
||||
assert vm.is_running()
|
||||
|
||||
|
||||
@@ -178,7 +197,9 @@ async def test_stop(vm):
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
|
||||
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
|
||||
nio = VPCS.instance().create_nio(
|
||||
{"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}}
|
||||
)
|
||||
await vm.port_add_nio_binding(0, nio)
|
||||
|
||||
await vm.start()
|
||||
@@ -211,7 +232,9 @@ async def test_reload(vm):
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
|
||||
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
|
||||
nio = VPCS.instance().create_nio(
|
||||
{"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}}
|
||||
)
|
||||
await vm.port_add_nio_binding(0, nio)
|
||||
await vm.start()
|
||||
assert vm.is_running()
|
||||
@@ -227,7 +250,9 @@ async def test_reload(vm):
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_nio_binding_udp(vm):
|
||||
|
||||
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
|
||||
nio = VPCS.instance().create_nio(
|
||||
{"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}}
|
||||
)
|
||||
await vm.port_add_nio_binding(0, nio)
|
||||
assert nio.lport == 4242
|
||||
|
||||
@@ -254,7 +279,7 @@ def test_update_startup_script(vm):
|
||||
|
||||
content = "echo GNS3 VPCS\nip 192.168.1.2\n"
|
||||
vm.startup_script = content
|
||||
filepath = os.path.join(vm.working_dir, 'startup.vpc')
|
||||
filepath = os.path.join(vm.working_dir, "startup.vpc")
|
||||
assert os.path.exists(filepath)
|
||||
with open(filepath) as f:
|
||||
assert f.read() == content
|
||||
@@ -290,8 +315,8 @@ def test_get_startup_script_using_default_script(vm):
|
||||
# Reset script file location
|
||||
vm._script_file = None
|
||||
|
||||
filepath = os.path.join(vm.working_dir, 'startup.vpc')
|
||||
with open(filepath, 'wb+') as f:
|
||||
filepath = os.path.join(vm.working_dir, "startup.vpc")
|
||||
with open(filepath, "wb+") as f:
|
||||
assert f.write(content.encode("utf-8"))
|
||||
|
||||
assert vm.startup_script == content
|
||||
@@ -300,16 +325,16 @@ def test_get_startup_script_using_default_script(vm):
|
||||
|
||||
def test_change_name(vm):
|
||||
|
||||
path = os.path.join(vm.working_dir, 'startup.vpc')
|
||||
path = os.path.join(vm.working_dir, "startup.vpc")
|
||||
vm.name = "world"
|
||||
with open(path, 'w+') as f:
|
||||
with open(path, "w+") as f:
|
||||
f.write("set pcname world")
|
||||
vm.name = "hello"
|
||||
assert vm.name == "hello"
|
||||
with open(path) as f:
|
||||
assert f.read() == "set pcname hello"
|
||||
# Support when the name is not sync with config
|
||||
with open(path, 'w+') as f:
|
||||
with open(path, "w+") as f:
|
||||
f.write("set pcname alpha")
|
||||
vm.name = "beta"
|
||||
assert vm.name == "beta"
|
||||
|
||||
Reference in new issue
Block a user