mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-10-23 11:22:21 +03:00
feat: add QEMU support documentation and enforce minimum version requirement
This commit is contained in:
parent
aab5432a5f
commit
a82b06d676
28
docs/dependencies/qemu.md
Normal file
28
docs/dependencies/qemu.md
Normal file
@ -0,0 +1,28 @@
|
||||
# QEMU support
|
||||
|
||||
GNS3 server requires QEMU 6.2 or newer. This is the minimum QEMU version that the server actively supports on Linux.
|
||||
|
||||
For compatibility checks, the project evaluates the Linux distributions that are commonly used in server deployments and that still have supported releases: CentOS Stream, Debian, Fedora, openSUSE, RHEL, SLES, and Ubuntu LTS. Other distributions are assumed to ship similar package versions and are treated by the same rule: if the distro ships QEMU 6.2 or newer, it is considered compatible; if it ships an older version, it is not supported by GNS3 server.
|
||||
|
||||
This document reflects the currently supported release set as of October 2026, based on the active releases listed by the major distro end-of-life trackers and package versions shipped by those releases.
|
||||
|
||||
## Minimum supported version
|
||||
|
||||
- Minimum supported QEMU version: 6.2
|
||||
- QEMU 6.2 was first shipped in Ubuntu 22.04 LTS and is the baseline used to determine whether a Linux distribution is suitable for GNS3 server.
|
||||
- Distributions shipping QEMU 6.2 or later are generally acceptable.
|
||||
- Older package versions are considered unsupported by policy.
|
||||
|
||||
## Currently supported Linux releases and shipped QEMU versions
|
||||
|
||||
The following supported releases are the current reference points used by the project. They are based on the active release lists published by the distributions' end-of-life trackers and the QEMU versions typically shipped by those releases.
|
||||
|
||||
| Distribution | Current supported OS release(s) | QEMU version shipped | Source |
|
||||
| --- | --- | --- | --- |
|
||||
| Ubuntu LTS | 24.04 LTS, 22.04 LTS | 8.2 for 24.04, 6.2 for 22.04 | https://endoflife.date/ubuntu |
|
||||
| Debian | 13 (trixie), 12 (bookworm) | 9.x for 13, 7.2 for 12 | https://endoflife.date/debian |
|
||||
| Fedora | 42, 41, 40 | 9.x | https://endoflife.date/fedora |
|
||||
| openSUSE | Leap 15.6, Tumbleweed | 8.x to 9.x | https://endoflife.date/opensuse |
|
||||
| CentOS Stream | 10, 9 | 9.x / 8.x | https://endoflife.date/centos |
|
||||
| RHEL | 10, 9.5, 9.4 | 9.x / 8.x | https://endoflife.date/redhat-enterprise-linux |
|
||||
| SLES | 15 SP7, 15 SP6 | 8.x | https://endoflife.date/sles |
|
||||
@ -2316,16 +2316,7 @@ class QemuVM(KernelDatapathMixin, BaseNode):
|
||||
f"file={disk},if=none,id=drive{disk_index},index={disk_index},media=disk{extra_drive_options}",
|
||||
]
|
||||
)
|
||||
if self._qemu_version and parse_version(self._qemu_version) >= parse_version("4.2.0"):
|
||||
# The ‘ide-drive’ device is deprecated since version 4.2.0
|
||||
# https://qemu.readthedocs.io/en/latest/system/deprecated.html#ide-drive-since-4-2
|
||||
options.extend(
|
||||
["-device", f"ide-hd,drive=drive{disk_index},bus=ahci{disk_index}.0,id=drive{disk_index}"]
|
||||
)
|
||||
else:
|
||||
options.extend(
|
||||
["-device", f"ide-drive,drive=drive{disk_index},bus=ahci{disk_index}.0,id=drive{disk_index}"]
|
||||
)
|
||||
options.extend(["-device", f"ide-hd,drive=drive{disk_index},bus=ahci{disk_index}.0,id=drive{disk_index}"])
|
||||
elif interface == "nvme":
|
||||
options.extend(
|
||||
[
|
||||
@ -2721,15 +2712,12 @@ class QemuVM(KernelDatapathMixin, BaseNode):
|
||||
|
||||
async def _disable_graphics(self):
|
||||
"""
|
||||
Disable graphics depending of the QEMU version
|
||||
Disable graphics for Qemu if no graphics options are specified.
|
||||
"""
|
||||
|
||||
if any(opt in self._options for opt in ["-display", "-nographic", "-curses", "-sdl-spice", "-vnc"]):
|
||||
return []
|
||||
if self._qemu_version and parse_version(self._qemu_version) >= parse_version("3.0"):
|
||||
return ["-display", "none"]
|
||||
else:
|
||||
return ["-nographic"]
|
||||
return ["-display", "none"]
|
||||
|
||||
async def _run_with_hardware_acceleration(self, qemu_path, options):
|
||||
"""
|
||||
@ -2854,8 +2842,8 @@ class QemuVM(KernelDatapathMixin, 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")
|
||||
if self._qemu_version and parse_version(self._qemu_version) < parse_version("6.2.0"):
|
||||
raise QemuError("Qemu version 6.2 or later is required to run Qemu VMs")
|
||||
vm_name = self._name.replace(",", ",,")
|
||||
project_path = self.project.path.replace(",", ",,")
|
||||
additional_options = self._options.strip()
|
||||
@ -2877,14 +2865,6 @@ class QemuVM(KernelDatapathMixin, BaseNode):
|
||||
if await self._run_with_hardware_acceleration(self.qemu_path, self._options):
|
||||
if sys.platform.startswith("linux"):
|
||||
command.extend(["-enable-kvm"])
|
||||
# Issue on some combo Intel CPU + KVM + Qemu 2.4.0
|
||||
# https://github.com/GNS3/gns3-server/issues/685
|
||||
if (
|
||||
self._qemu_version
|
||||
and parse_version(self._qemu_version) >= parse_version("2.4.0")
|
||||
and self.platform == "x86_64"
|
||||
):
|
||||
command.extend(["-machine", "smm=off"])
|
||||
elif sys.platform.startswith("darwin"):
|
||||
command.extend(["-enable-hax"])
|
||||
command.extend(["-boot", f"order={self._boot_priority}"])
|
||||
|
||||
@ -645,7 +645,7 @@ async def test_build_command_console_none(vm):
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_command_manual_uuid(vm):
|
||||
"""
|
||||
If user has set a uuid we keep it
|
||||
If user has set a UUID we keep it
|
||||
"""
|
||||
|
||||
vm.options = "-uuid e1c307a4-896f-11e6-81a5-3c07547807cc"
|
||||
@ -657,75 +657,34 @@ async def test_build_command_manual_uuid(vm):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_command_kvm_below_2_4(linux_platform, vm, fake_qemu_binary):
|
||||
async def test_build_command_kvm_below_6_2(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")
|
||||
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="6.1.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()):
|
||||
with pytest.raises(QemuError):
|
||||
await vm._build_command()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_command_kvm_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.4.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",
|
||||
"-machine",
|
||||
"smm=off",
|
||||
"-boot",
|
||||
"order=c",
|
||||
"-uuid",
|
||||
vm.id,
|
||||
"-serial",
|
||||
f"telnet:127.0.0.1:{vm._internal_console_port},server,nowait",
|
||||
"-net",
|
||||
"none",
|
||||
"-device",
|
||||
"i82801b11-bridge,id=dmi_pci_bridge1",
|
||||
"-device",
|
||||
"pci-bridge,id=pci-bridge1,bus=dmi_pci_bridge1,chassis_nr=0x1,addr=0x1,shpc=off",
|
||||
"-device",
|
||||
f"e1000,mac={vm._mac_address},bus=pci-bridge1,addr=0x00,netdev=gns3-0",
|
||||
"-netdev",
|
||||
f"socket,id=gns3-0,udp=127.0.0.1:{nio.rport},localaddr=127.0.0.1:{nio.lport}",
|
||||
"-nographic",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_command_without_display(vm):
|
||||
|
||||
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.5.0")
|
||||
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="6.2.0")
|
||||
os.environ["DISPLAY"] = ""
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
|
||||
cmd = await vm._build_command()
|
||||
assert "-nographic" in cmd
|
||||
print(cmd)
|
||||
assert "-display" in cmd
|
||||
assert "none" in cmd
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_command_two_adapters(vm, fake_qemu_binary):
|
||||
|
||||
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.5.0")
|
||||
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="6.2.0")
|
||||
os.environ["DISPLAY"] = "0:0"
|
||||
vm.adapters = 2
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
|
||||
@ -760,7 +719,8 @@ async def test_build_command_two_adapters(vm, fake_qemu_binary):
|
||||
f"e1000,mac={int_to_macaddress(macaddress_to_int(vm._mac_address) + 1)},bus=pci-bridge1,addr=0x01,netdev=gns3-1",
|
||||
"-netdev",
|
||||
f"socket,id=gns3-1,udp=127.0.0.1:{nio2.rport},localaddr=127.0.0.1:{nio2.lport}",
|
||||
"-nographic",
|
||||
"-display",
|
||||
"none",
|
||||
]
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user