From 2b96e5462900ac52801af64dd04dc1f5b35a83cf Mon Sep 17 00:00:00 2001 From: grossmj Date: Wed, 30 Apr 2025 13:38:52 +0700 Subject: [PATCH] Fix tests and require Qemu version >= 2.4 --- gns3server/compute/qemu/qemu_vm.py | 10 +--- tests/compute/qemu/test_qemu_vm.py | 81 ++++++++++++------------------ 2 files changed, 33 insertions(+), 58 deletions(-) diff --git a/gns3server/compute/qemu/qemu_vm.py b/gns3server/compute/qemu/qemu_vm.py index a2c51935..e9981ac4 100644 --- a/gns3server/compute/qemu/qemu_vm.py +++ b/gns3server/compute/qemu/qemu_vm.py @@ -2450,15 +2450,7 @@ class QemuVM(BaseNode): # and pci_bridges also consume IDs. # Move network devices to their own bridge pci_devices_reserved = 32 - pci_devices = pci_devices_reserved + len(self._ethernet_adapters) - pci_bridges = math.floor(pci_devices / 32) pci_bridges_created = 0 - if pci_bridges >= 1: - if self._qemu_version and parse_version(self._qemu_version) < parse_version("2.4.0"): - raise QemuError( - "Qemu version 2.4 or later is required to run this VM with a large number of network adapters" - ) - pci_device_id = pci_devices_reserved for adapter_number, adapter in enumerate(self._ethernet_adapters): mac = int_to_macaddress(macaddress_to_int(self._mac_address) + adapter_number) @@ -2650,6 +2642,8 @@ class QemuVM(BaseNode): """ self._qemu_version = await self.manager.get_qemu_version(self.qemu_path) + if self._qemu_version and parse_version(self._qemu_version) < parse_version("2.4.0"): + raise QemuError("Qemu version 2.4 or later is required to run Qemu VMs") vm_name = self._name.replace(",", ",,") project_path = self.project.path.replace(",", ",,") additional_options = self._options.strip() diff --git a/tests/compute/qemu/test_qemu_vm.py b/tests/compute/qemu/test_qemu_vm.py index 11f11e73..71aae766 100644 --- a/tests/compute/qemu/test_qemu_vm.py +++ b/tests/compute/qemu/test_qemu_vm.py @@ -570,7 +570,11 @@ async def test_build_command(vm, fake_qemu_binary): "-net", "none", "-device", - "e1000,mac={},netdev=gns3-0".format(vm._mac_address), + "i82801b11-bridge,id=dmi_pci_bridge1", + "-device", + "pci-bridge,id=pci-bridge1,bus=dmi_pci_bridge1,chassis_nr=0x1,addr=0x1,shpc=off", + "-device", + "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), "-display", @@ -593,40 +597,16 @@ async def test_build_command_manual_uuid(vm): @pytest.mark.asyncio -async def test_build_command_kvm(linux_platform, vm, fake_qemu_binary): +async def test_build_command_kvm_below_2_4(linux_platform, vm, fake_qemu_binary): """ Qemu 2.4 introduce an issue with KVM """ vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.3.2") - os.environ["DISPLAY"] = "0:0" with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM._run_with_hardware_acceleration", return_value=True): - with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - cmd = await vm._build_command() - nio = vm._local_udp_tunnels[0][0] - assert cmd == [ - fake_qemu_binary, - "-name", - "test", - "-m", - "256M", - "-smp", - "cpus=1,maxcpus=1,sockets=1", - "-enable-kvm", - "-boot", - "order=c", - "-uuid", - vm.id, - "-serial", - "telnet:127.0.0.1:{},server,nowait".format(vm._internal_console_port), - "-net", - "none", - "-device", - "e1000,mac={},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" - ] + with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): + with pytest.raises(QemuError): + await vm._build_command() @pytest.mark.asyncio @@ -661,7 +641,11 @@ async def test_build_command_kvm_2_4(linux_platform, vm, fake_qemu_binary): "-net", "none", "-device", - "e1000,mac={},netdev=gns3-0".format(vm._mac_address), + "i82801b11-bridge,id=dmi_pci_bridge1", + "-device", + "pci-bridge,id=pci-bridge1,bus=dmi_pci_bridge1,chassis_nr=0x1,addr=0x1,shpc=off", + "-device", + "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" @@ -705,11 +689,15 @@ async def test_build_command_two_adapters(vm, fake_qemu_binary): "-net", "none", "-device", - "e1000,mac={},netdev=gns3-0".format(vm._mac_address), + "i82801b11-bridge,id=dmi_pci_bridge1", + "-device", + "pci-bridge,id=pci-bridge1,bus=dmi_pci_bridge1,chassis_nr=0x1,addr=0x1,shpc=off", + "-device", + "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(nio1.rport, nio1.lport), "-device", - "e1000,mac={},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" @@ -729,8 +717,8 @@ async def test_build_command_two_adapters_mac_address(vm): assert mac_0[:8] == "00:00:ab" with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): cmd = await vm._build_command() - assert "e1000,mac={},netdev=gns3-0".format(mac_0) in cmd - assert "e1000,mac={},netdev=gns3-1".format(mac_1) in cmd + 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 vm.mac_address = "00:42:ab:0e:0f:0a" mac_0 = vm._mac_address @@ -739,8 +727,8 @@ async def test_build_command_two_adapters_mac_address(vm): with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): cmd = await vm._build_command() - assert "e1000,mac={},netdev=gns3-0".format(mac_0) in cmd - assert "e1000,mac={},netdev=gns3-1".format(mac_1) in cmd + 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 @pytest.mark.asyncio @@ -762,28 +750,20 @@ async def test_build_command_large_number_of_adapters(vm): assert len([l for l in cmd if "e1000" in l ]) == 100 assert len(vm._ethernet_adapters) == 100 - assert "e1000,mac={},netdev=gns3-0".format(mac_0) in cmd - assert "e1000,mac={},netdev=gns3-1".format(mac_1) in cmd + 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 assert "pci-bridge,id=pci-bridge0,bus=dmi_pci_bridge0,chassis_nr=0x1,addr=0x0,shpc=off" not in cmd assert "pci-bridge,id=pci-bridge1,bus=dmi_pci_bridge1,chassis_nr=0x1,addr=0x1,shpc=off" in cmd assert "pci-bridge,id=pci-bridge2,bus=dmi_pci_bridge2,chassis_nr=0x1,addr=0x2,shpc=off" in cmd assert "i82801b11-bridge,id=dmi_pci_bridge1" in cmd mac_29 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 29) - assert "e1000,mac={},bus=pci-bridge1,addr=0x04,netdev=gns3-29".format(mac_29) in cmd + assert "e1000,mac={},bus=pci-bridge1,addr=0x1d,netdev=gns3-29".format(mac_29) in cmd mac_30 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 30) - assert "e1000,mac={},bus=pci-bridge1,addr=0x05,netdev=gns3-30".format(mac_30) in cmd + assert "e1000,mac={},bus=pci-bridge1,addr=0x1e,netdev=gns3-30".format(mac_30) in cmd mac_74 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 74) - assert "e1000,mac={},bus=pci-bridge2,addr=0x11,netdev=gns3-74".format(mac_74) in cmd + assert "e1000,mac={},bus=pci-bridge3,addr=0x0a,netdev=gns3-74".format(mac_74) in cmd - # Qemu < 2.4 doesn't support large number of adapters - vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.0.0") - with pytest.raises(QemuError): - with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): - await vm._build_command() - vm.adapters = 5 - with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): - await vm._build_command() @pytest.mark.asyncio async def test_build_command_with_virtio_net_pci_adapter(vm): @@ -796,7 +776,8 @@ async def test_build_command_with_virtio_net_pci_adapter(vm): vm._adapter_type = "virtio-net-pci" with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): cmd = await vm._build_command() - assert "virtio-net-pci,mac=00:00:ab:0e:0f:09,speed=10000,duplex=full,netdev=gns3-0" in cmd + print(cmd) + assert "virtio-net-pci,mac=00:00:ab:0e:0f:09,speed=10000,duplex=full,bus=pci-bridge1,addr=0x00,netdev=gns3-0" in cmd @pytest.mark.asyncio