Compare commits

...
15 Commits
Author SHA1 Message Date
grossmj 803cc17410 Release v2.2.60 2026-07-15 18:36:26 +02:00
grossmj f088c55cfe Sync appliances 2026-07-15 18:32:12 +02:00
Jeremy Grossmann 8a8864c90b Merge pull request #2814 from GNS3/bugfix/2783
fix(import): project import does not move images symlinks into place
2026-07-15 09:53:15 +02:00
grossmj 1986bce538 Only set IOU images to be executable when importing images 2026-07-15 09:43:34 +02:00
grossmj c528d2cd95 fix(import): project import does not move images symlinks into place 2026-07-13 18:19:52 +02:00
Jeremy Grossmann 7529ee4168 Merge pull request #2813 from GNS3/uefi-improvements
UEFI improvements for Qemu VMs
2026-07-13 12:05:07 +02:00
grossmj 61c7f4469d Search for system UEFI that is compatible with Python < 3.12 2026-07-13 11:34:29 +02:00
grossmj 896b4fc56a UEFI improvements for Qemu VMs
* Add OVMF firmware directory configuration
* Automatically add a Random Number Generator (RNG) device when using uefi option is enabled
2026-07-13 11:08:17 +02:00
grossmj a58fa8602b remove wrongly merged code 2026-07-13 10:05:01 +02:00
YueGuobin d8f8b6ec70 fix(docker): handle container name conflict automatically
When a Docker container with the same name already exists (e.g., from a
   previous crashed GNS3 session), Docker returns a 409 Conflict error
   when trying to create a new container with that name. This causes the
   project open operation to fail.

   This fix adds automatic cleanup of stale containers when encountering
   a name conflict:
   - Added DockerHttp409Error exception class
   - Updated http_query to detect 409 status codes
   - Modified create() to remove conflicting containers and retry

   Fixes the issue where opening a project fails with:
   "Docker has returned an error: 409 Conflict. The container name
   '/GNS3.xxx' is already in use by container 'xxx'"
2026-07-13 09:57:55 +02:00
Jeremy Grossmann b256d5a5f6 Merge pull request #2812 from GNS3/bugfix/2788
fix: gns3-server crashes on startup if "Open this project in the background" is active but there is a problem with that project
2026-07-12 13:50:11 +02:00
grossmj ea09cc2724 fix: gns3-server crashes on startup if "Open this project in the background" is active but there is a problem with that project 2026-07-12 13:46:12 +02:00
grossmj e3e0a511b6 Handle HTTPNotFound exception when retrieving compute status 2026-07-12 11:08:13 +02:00
grossmj 0ecaab4da0 Replace ControllerForbiddenError with aiohttp.web.HTTPForbidden for project deletion error handling 2026-07-12 11:05:15 +02:00
YueGuobinandClaude Opus 4.6 40644f33e6 Fix: Check compute connectivity before open() during project deletion
Previously the disconnected compute check ran after open(), which would
block for 120s trying to connect to unreachable remote computes before
rejecting the deletion. Now reads the topology file directly to extract
compute IDs and checks connectivity before calling open(), enabling
immediate rejection of deletions involving offline computes.

Also removes the redundant post-open() check since the early check
covers both opened and closed project states.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-12 10:57:56 +02:00
17 changed files with 227 additions and 580 deletions

No files matched your search

+14
View File
@@ -1,5 +1,19 @@
# Change Log
## 2.2.60 15/07/2026
* Sync appliances
* Only set IOU images to be executable when importing images
* fix(import): project import does not move images symlinks into place
* Search for system UEFI that is compatible with Python < 3.12
* Add OVMF firmware directory configuration
* Automatically add a Random Number Generator (RNG) device when using uefi option is enabled
* fix(docker): handle container name conflict automatically
* fix: gns3-server crashes on startup if "Open this project in the background" is active but there is a problem with that project
* Handle HTTPNotFound exception when retrieving compute status
* Fix: Check compute connectivity before open() during project deletion
* API endpoints to manage base configuration files for templates
## 2.2.59 08/05/2026
* Sync appliances
+2
View File
@@ -103,6 +103,8 @@ enable_hardware_acceleration = True
require_hardware_acceleration = False
; Allow unsafe additional command line options
allow_unsafe_options = False
; Path to the OVMF firmware directory
ovmf_firmware_dir = "/usr/share/OVMF"
[VMware]
; First vmnet interface of the range that can be managed by the GNS3 server
+31 -16
View File
@@ -1,41 +1,56 @@
{
"appliance_id": "088df570-f637-46f5-8a68-85acde538e5e",
"appliance_id": "8fecbf89-5cd1-4aea-b735-5f36cf0efbb7",
"name": "BIRD",
"category": "router",
"description": "The BIRD project aims to develop a fully functional dynamic IP routing daemon primarily targeted on (but not limited to) Linux, FreeBSD and other UNIX-like systems and distributed under the GNU General Public License.",
"vendor_name": "CZ.NIC Labs",
"vendor_url": "http://bird.network.cz/",
"documentation_url": "http://bird.network.cz/?get_doc&f=bird.html",
"vendor_url": "https://bird.network.cz",
"documentation_url": "https://bird.network.cz/?get_doc&f=bird.html&v=20",
"product_name": "BIRD internet routing daemon",
"registry_version": 4,
"status": "stable",
"maintainer": "GNS3 Team",
"maintainer_email": "developers@gns3.net",
"usage": "\n*** BIRD v1 is end-of-life ***\nPlease use the BIRD2 appliance.\n\nConfigure interfaces in /opt/bootlocal.sh, BIRD configuration is done in /usr/local/etc/bird",
"maintainer": "Bernhard Ehlers",
"maintainer_email": "dev-ehlers@mailbox.org",
"usage": "Username:\tgns3\nPassword:\tgns3\nTo become root, use \"sudo -s\".\n\nNetwork configuration:\nsudo nano /etc/network/interfaces\nsudo systemctl restart networking\n\nBIRD:\nRestart: sudo systemctl restart bird\nReconfigure: birdc configure",
"port_name_format": "eth{0}",
"qemu": {
"adapter_type": "e1000",
"adapter_type": "virtio-net-pci",
"adapters": 4,
"ram": 128,
"hda_disk_interface": "ide",
"ram": 512,
"hda_disk_interface": "scsi",
"arch": "x86_64",
"console_type": "telnet",
"kvm": "allow"
},
"images": [
{
"filename": "bird-tinycore64-1.5.0.img",
"version": "1.5.0",
"md5sum": "08d50ba2b1b262e2e03e4babf90abf69",
"filesize": 22413312,
"filename": "bird2-debian-2.14.qcow2",
"version": "2.14",
"md5sum": "029cf1756201ee79497c169502b08b88",
"filesize": 303717376,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "http://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/bird-tinycore64-1.5.0.img"
"direct_download_url": "https://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/bird2-debian-2.14.qcow2"
},
{
"filename": "bird2-debian-2.0.12.qcow2",
"version": "2.0.12",
"md5sum": "435218a2e90cba921cc7fde1d64a9419",
"filesize": 287965184,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "https://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/bird2-debian-2.0.12.qcow2"
}
],
"versions": [
{
"name": "1.5.0",
"name": "2.14",
"images": {
"hda_disk_image": "bird-tinycore64-1.5.0.img"
"hda_disk_image": "bird2-debian-2.14.qcow2"
}
},
{
"name": "2.0.12",
"images": {
"hda_disk_image": "bird2-debian-2.0.12.qcow2"
}
}
]
-57
View File
@@ -1,57 +0,0 @@
{
"appliance_id": "8fecbf89-5cd1-4aea-b735-5f36cf0efbb7",
"name": "BIRD2",
"category": "router",
"description": "The BIRD project aims to develop a fully functional dynamic IP routing daemon primarily targeted on (but not limited to) Linux, FreeBSD and other UNIX-like systems and distributed under the GNU General Public License.",
"vendor_name": "CZ.NIC Labs",
"vendor_url": "https://bird.network.cz",
"documentation_url": "https://bird.network.cz/?get_doc&f=bird.html&v=20",
"product_name": "BIRD internet routing daemon",
"registry_version": 4,
"status": "stable",
"maintainer": "Bernhard Ehlers",
"maintainer_email": "dev-ehlers@mailbox.org",
"usage": "Username:\tgns3\nPassword:\tgns3\nTo become root, use \"sudo -s\".\n\nNetwork configuration:\nsudo nano /etc/network/interfaces\nsudo systemctl restart networking\n\nBIRD:\nRestart: sudo systemctl restart bird\nReconfigure: birdc configure",
"port_name_format": "eth{0}",
"qemu": {
"adapter_type": "virtio-net-pci",
"adapters": 4,
"ram": 512,
"hda_disk_interface": "scsi",
"arch": "x86_64",
"console_type": "telnet",
"kvm": "allow"
},
"images": [
{
"filename": "bird2-debian-2.14.qcow2",
"version": "2.14",
"md5sum": "029cf1756201ee79497c169502b08b88",
"filesize": 303717376,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "https://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/bird2-debian-2.14.qcow2"
},
{
"filename": "bird2-debian-2.0.12.qcow2",
"version": "2.0.12",
"md5sum": "435218a2e90cba921cc7fde1d64a9419",
"filesize": 287965184,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "https://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/bird2-debian-2.0.12.qcow2"
}
],
"versions": [
{
"name": "2.14",
"images": {
"hda_disk_image": "bird2-debian-2.14.qcow2"
}
},
{
"name": "2.0.12",
"images": {
"hda_disk_image": "bird2-debian-2.0.12.qcow2"
}
}
]
}
+7 -483
View File
@@ -51,250 +51,12 @@
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.4.3-build2487-FORTINET.out.kvm.qcow2",
"version": "7.4.3",
"md5sum": "b01d9f86aa27c538407d518df1326863",
"filesize": 346107904,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.4.2-build2397-FORTINET.out.kvm.qcow2",
"version": "7.4.2",
"md5sum": "36371fbf06210ded57c00b2ff290f2c5",
"filesize": 322514944,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.4.1-build2308-FORTINET.out.kvm.qcow2",
"version": "7.4.1",
"md5sum": "e542cc8f2d8f46e9c32b783bf31bef39",
"filesize": 309387264,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.2.5-build1574-FORTINET.out.kvm.qcow2",
"version": "7.2.5",
"md5sum": "754326845096afd909ec45d98f8d5a83",
"filesize": 278401024,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.2.4-build1460-FORTINET.out.kvm.qcow2",
"version": "7.2.4",
"md5sum": "98fa9830d9ecb5911a703d03b80026b6",
"filesize": 261992448,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.2.2-build1334-FORTINET.out.kvm.qcow2",
"version": "7.2.2",
"md5sum": "2ff1298257321cd485d2cad91d6ce510",
"filesize": 246083584,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.2.1-build1215-FORTINET.out.kvm.qcow2",
"version": "7.2.1",
"md5sum": "1a3eeff1204fa8f4243773f7521e12b5",
"filesize": 242814976,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.0.12-build0623-FORTINET.out.kvm.qcow2",
"version": "7.0.12",
"md5sum": "5b6f6a2b8bc00e56337aa7023a9025cf",
"filesize": 249520128,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.0.11-build0595-FORTINET.out.kvm.qcow2",
"version": "7.0.11",
"md5sum": "7b166222136e26190159f37cccbaab6e",
"filesize": 249360384,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.0.9-build0489-FORTINET.out.kvm.qcow2",
"version": "7.0.9",
"md5sum": "dbeb6a79b6e421000573dbbbdb50b8b5",
"filesize": 247955456,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.0.6-build0372-FORTINET.out.kvm.qcow2",
"version": "7.0.6",
"md5sum": "dfa4df9e976ed87e73cb9601a8a70323",
"filesize": 239190016,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.0.5-build0365-FORTINET.out.kvm.qcow2",
"version": "7.0.5",
"md5sum": "e8b9c992784cea766b52a427a5fe0279",
"filesize": 237535232,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6.4.14-build2660-FORTINET.out.kvm.qcow2",
"version": "6.4.14",
"md5sum": "0fe56e363b166c07b710bde795e36049",
"filesize": 219430912,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6.4.12-build2610-FORTINET.out.kvm.qcow2",
"version": "6.4.12",
"md5sum": "36c0dc531d921e5f1e1e09b030f7c813",
"filesize": 219455488,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6-build2288-FORTINET.out.kvm.qcow2",
"version": "6.4.5",
"md5sum": "bd2791984b03f55a6825297e83c6576a",
"filesize": 117014528,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6-build2253-FORTINET.out.kvm.qcow2",
"version": "6.4.4",
"md5sum": "3554a47fde2dc91d17eec16fd0dc10a3",
"filesize": 116621312,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6-build1183-FORTINET.out.kvm.qcow2",
"version": "6.2.2",
"md5sum": "f5051a8fe49d916bb554b9bae32a1eb4",
"filesize": 139145216,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6-build1050-FORTINET.out.kvm.qcow2",
"version": "6.2.0",
"md5sum": "c19d2527f91ad1bbafbde5bf08487867",
"filesize": 126894080,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6-build0349-FORTINET.out.kvm.qcow2",
"version": "6.0.6",
"md5sum": "d03f024c948ba6e2bb9e66c11ca8f34c",
"filesize": 112553984,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6-build0255-FORTINET.out.kvm.qcow2",
"version": "6.0.3",
"md5sum": "5f34d52d9289b0be2a4c04943446ea39",
"filesize": 115703808,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6-build0205-FORTINET.out.kvm.qcow2",
"version": "6.0.2",
"md5sum": "8f748649c537d9b5466b24c5b4e62017",
"filesize": 116981760,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6-build0092-FORTINET.out.kvm.qcow2",
"version": "6.0.0",
"md5sum": "73bfe1bc70124521a524d857646b9c2e",
"filesize": 119066624,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v5-build1631-FORTINET.out.kvm.qcow2",
"version": "5.6.2",
"md5sum": "c81cc247e8eb03249b475fe0e847653e",
"filesize": 106946560,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v5-build1619-FORTINET.out.kvm.qcow2",
"version": "5.6.1",
"md5sum": "8cc553842564d232af295d6a0c784c1f",
"filesize": 106831872,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v5-build1557-FORTINET.out.kvm.qcow2",
"version": "5.6.0",
"md5sum": "f8bd600796f894f4ca1ea2d6b4066d3d",
"filesize": 108363776,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v5-build1225-FORTINET.out.kvm.qcow2",
"version": "5.4.4",
"md5sum": "53bc6e320fe7bde5d2b636bde95a910c",
"filesize": 89911296,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v5-build1187-FORTINET.out.kvm.qcow2",
"version": "5.4.3",
"md5sum": "53602c776d215d98e32163a10804fc49",
"filesize": 87425024,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v5-build1151-FORTINET.out.kvm.qcow2",
"version": "5.4.2",
"md5sum": "8e131ad40009c740f3efdee6dc3a0ac3",
"filesize": 86437888,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v5-build1082-FORTINET.out.kvm.qcow2",
"version": "5.4.1",
"md5sum": "fc1815410f3f0536e2e3a9c1c5c07f41",
"filesize": 83124224,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v5-build1019-FORTINET.out.kvm.qcow2",
"version": "5.4.0",
"md5sum": "1cfb22671cb372d8bf3e47b9c3c55ded",
"filesize": 77541376,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v5-build0786-FORTINET.out.kvm.qcow2",
"version": "5.2.10",
"md5sum": "377fe38bf07bc2435608e5b65f780f07",
"filesize": 64962560,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v5-build0780-FORTINET.out.kvm.qcow2",
"version": "5.2.9",
"md5sum": "04268e779d3d5e6c928c6fd638423c52",
"filesize": 65007616,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v5-build0777-FORTINET.out.kvm.qcow2",
"version": "5.2.8",
"md5sum": "6dbf148ace9bf309ad383757afd75fad",
"filesize": 65011712,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v5-build0757-FORTINET.out.kvm.qcow2",
"version": "5.2.7",
"md5sum": "d37dbaa49d7522324681eeba19f7699b",
"filesize": 65056768,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "empty30G.qcow2",
"filename": "empty500G.qcow2",
"version": "1.0",
"md5sum": "3411a599e822f2ac6be560a26405821a",
"filesize": 197120,
"md5sum": "658c825441b9b3080ba00f9eec002eaa",
"filesize": 204608,
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/",
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty30G.qcow2/download"
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty500G.qcow2/download"
}
],
"versions": [
@@ -302,259 +64,21 @@
"name": "7.4.6",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.4.6.M-build2588-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
"hdb_disk_image": "empty500G.qcow2"
}
},
{
"name": "7.4.5",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.4.5.M-build2553-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
"hdb_disk_image": "empty500G.qcow2"
}
},
{
"name": "7.4.4",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.4.4.F-build2550-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.4.3",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.4.3-build2487-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.4.2",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.4.2-build2397-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.4.1",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.4.1-build2308-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.5",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.2.5-build1574-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.4",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.2.4-build1460-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.2",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.2.2-build1334-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.1",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.2.1-build1215-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.12",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.0.12-build0623-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.11",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.0.11-build0595-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.9",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.0.9-build0489-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.6",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.0.6-build0372-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.5",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.0.5-build0365-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.14",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v6.4.14-build2660-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.12",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v6.4.12-build2610-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.5",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v6-build2288-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.4",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v6-build2253-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.2.2",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v6-build1183-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.2.0",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v6-build1050-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.0.6",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v6-build0349-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.0.3",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v6-build0255-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.0.2",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v6-build0205-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.0.0",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v6-build0092-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "5.6.2",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v5-build1631-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "5.6.1",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v5-build1619-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "5.6.0",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v5-build1557-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "5.4.4",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v5-build1225-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "5.4.3",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v5-build1187-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "5.4.2",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v5-build1151-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "5.4.1",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v5-build1082-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "5.4.0",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v5-build1019-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "5.2.10",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v5-build0786-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "5.2.9",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v5-build0780-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "5.2.8",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v5-build0777-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "5.2.7",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v5-build0757-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
"hdb_disk_image": "empty500G.qcow2"
}
}
]
+28
View File
@@ -132,9 +132,37 @@
"md5sum": "24cd1006734993dab338e5c75f80b875",
"version": "26.03.0",
"direct_download_url": "https://github.com/kernelkit/infix/releases/download/v26.03.0/infix-x86_64-v26.03.0.qcow2"
},
{
"filename": "infix-x86_64-v26.05.0.qcow2",
"filesize": 330039296,
"md5sum": "60f7c36c389c33ab108acc021f41ccd5",
"version": "26.05.0",
"direct_download_url": "https://github.com/kernelkit/infix/releases/download/v26.05.0/infix-x86_64-v26.05.0.qcow2"
},
{
"filename": "infix-x86_64-v26.06.0.qcow2",
"filesize": 363593728,
"md5sum": "79ca8bd8534bbaa1af0ab874a49d6f4c",
"version": "26.06.0",
"direct_download_url": "https://github.com/kernelkit/infix/releases/download/v26.06.0/infix-x86_64-v26.06.0.qcow2"
}
],
"versions": [
{
"name": "26.06.0",
"images": {
"bios_image": "OVMF-edk2-stable202305.fd",
"hda_disk_image": "infix-x86_64-v26.06.0.qcow2"
}
},
{
"name": "26.05.0",
"images": {
"bios_image": "OVMF-edk2-stable202305.fd",
"hda_disk_image": "infix-x86_64-v26.05.0.qcow2"
}
},
{
"name": "26.03.0",
"images": {
+1 -1
View File
@@ -14,7 +14,7 @@
"symbol": "linux_guest.svg",
"docker": {
"adapters": 1,
"image": "gns3/ubuntu:noble",
"image": "gns3/ubuntu:resolute",
"console_type": "telnet"
}
}
+14
View File
@@ -38,6 +38,13 @@
"filesize": 17825792,
"direct_download_url": "https://dropzone.westermo.com/file.aspx?id=e6a7676d-85a7-4374-8961-c68aacb74921"
},
{
"filename": "WeOS-zero-5.29.0.disk",
"version": "5.29.0",
"filesize": 81788928,
"md5sum": "f464de7b2b424f4a8ad7c650108fee3d",
"direct_download_url": "https://dropzone.westermo.com/file.aspx?id=52655074-0fab-4119-ba01-b68200a733ab"
},
{
"filename": "WeOS-zero-5.28.0.disk",
"version": "5.28.0",
@@ -54,6 +61,13 @@
}
],
"versions": [
{
"name": "5.29.0",
"images": {
"hda_disk_image": "WeOS-zero-5.29.0.disk",
"hdb_disk_image": "Config-zero-1.0.0.disk"
}
},
{
"name": "5.28.0",
"images": {
+3 -1
View File
@@ -33,7 +33,7 @@ from gns3server.config import Config
from gns3server.utils.asyncio import locking
from gns3server.compute.base_manager import BaseManager
from gns3server.compute.docker.docker_vm import DockerVM
from gns3server.compute.docker.docker_error import DockerError, DockerHttp304Error, DockerHttp404Error
from gns3server.compute.docker.docker_error import DockerError, DockerHttp304Error, DockerHttp404Error, DockerHttp409Error
log = logging.getLogger(__name__)
@@ -236,6 +236,8 @@ class Docker(BaseManager):
raise DockerHttp304Error("Docker has returned an error: {} {}".format(response.status, body))
elif response.status == 404:
raise DockerHttp404Error("Docker has returned an error: {} {}".format(response.status, body))
elif response.status == 409:
raise DockerHttp409Error("Docker has returned an error: {} {}".format(response.status, body))
else:
raise DockerError("Docker has returned an error: {} {}".format(response.status, body))
return response
@@ -32,3 +32,7 @@ class DockerHttp304Error(DockerError):
class DockerHttp404Error(DockerError):
pass
class DockerHttp409Error(DockerError):
pass
+27 -5
View File
@@ -43,7 +43,8 @@ from ..nios.nio_udp import NIOUDP
from .docker_error import (
DockerError,
DockerHttp304Error,
DockerHttp404Error
DockerHttp404Error,
DockerHttp409Error
)
import logging
@@ -459,10 +460,31 @@ class DockerVM(BaseNode):
if extra_hosts:
params["Env"].append("GNS3_EXTRA_HOSTS={}".format(extra_hosts))
# Support name in Doker: [a-zA-Z0-9][a-zA-Z0-9_.-]
result = await self.manager.query("POST", "containers/create?name={}".format(self.docker_name), data=params)
self._cid = result['Id']
log.info("Docker container '{name}' [{id}] created".format(name=self._name, id=self._id))
try:
# Supported names in Docker: [a-zA-Z0-9][a-zA-Z0-9_.-]
result = await self.manager.query("POST", f"containers/create?name={self.docker_name}", data=params)
except DockerHttp409Error:
# Container name already exists. This can happen when the server crashes
# and leaves containers behind. Try to remove the conflicting container.
log.warning(f"Container name '{self.docker_name}' is already in use, attempting to clean up the stale container...")
try:
# Try to get and remove the conflicting container
try:
container_info = await self.manager.query("GET", f"containers/{self.docker_name}/json")
container_id = container_info["Id"]
# Force remove the container
await self.manager.query("DELETE", f"containers/{container_id}", params={"force": 1, "v": 1})
log.info(f"Removed stale container '{self.docker_name}' ({container_id})")
except DockerHttp404Error:
# Container doesn't exist anymore, race condition - just continue
pass
# Retry creating the container
result = await self.manager.query("POST", f"containers/create?name={self.docker_name}", data=params)
except DockerError as e:
log.error(f"Failed to clean up conflicting container '{self.docker_name}': {e}")
raise
self._cid = result["Id"]
log.info(f"Docker container '{self._name}' [{self._id}] created")
return True
def _format_env(self, variables, env):
+24 -7
View File
@@ -35,6 +35,7 @@ import time
import json
import psutil
from pathlib import Path
from gns3server.utils import parse_version, shlex_quote
from gns3server.utils.asyncio import subprocess_check_output, cancellable_wait_run_in_executor
from .qemu_error import QemuError
@@ -2057,15 +2058,23 @@ class QemuVM(BaseNode):
options.extend(["-bios", self._bios_image.replace(",", ",,")])
elif self._uefi:
ovmf_firmware_dir = self._manager.config.get_section_config("Qemu").get("ovmf_firmware_dir", "/usr/share/OVMF")
system_ovmf_firmware_dir = Path(ovmf_firmware_dir)
log.info("Using OVMF firmware directory: {}".format(system_ovmf_firmware_dir))
old_ovmf_vars_path = os.path.join(self.working_dir, "OVMF_VARS.fd")
if os.path.exists(old_ovmf_vars_path):
# the node has its own UEFI variables store already, we must also use the old UEFI firmware
ovmf_firmware_path = self.manager.get_abs_image_path("OVMF_CODE.fd")
else:
system_ovmf_firmware_path = "/usr/share/OVMF/OVMF_CODE_4M.fd"
if os.path.exists(system_ovmf_firmware_path):
ovmf_firmware_path = system_ovmf_firmware_path
# Use a manual case-insensitive search instead
try:
system_ovmf_firmware_path = next((f for f in system_ovmf_firmware_dir.glob("*.fd")
if f.name.lower() == "ovmf_code_4m.fd"), None)
except (FileNotFoundError, StopIteration):
system_ovmf_firmware_path = None
if system_ovmf_firmware_path:
ovmf_firmware_path = str(system_ovmf_firmware_path)
else:
# otherwise, get the UEFI firmware from the images directory
ovmf_firmware_path = self.manager.get_abs_image_path("OVMF_CODE_4M.fd")
@@ -2074,9 +2083,13 @@ class QemuVM(BaseNode):
options.extend(["-drive", "if=pflash,format=raw,readonly,file={}".format(ovmf_firmware_path)])
# try to use the UEFI variables store from the system first
system_ovmf_vars_path = "/usr/share/OVMF/OVMF_VARS_4M.fd"
if os.path.exists(system_ovmf_vars_path):
ovmf_vars_path = system_ovmf_vars_path
try:
system_ovmf_vars_path = next((f for f in system_ovmf_firmware_dir.glob("*.fd")
if f.name.lower() == "ovmf_vars_4m.fd"), None)
except (FileNotFoundError, StopIteration):
system_ovmf_vars_path = None
if system_ovmf_vars_path:
ovmf_vars_path = str(system_ovmf_vars_path)
else:
# otherwise, get the UEFI variables store from the images directory
ovmf_vars_path = self.manager.get_abs_image_path("OVMF_VARS_4M.fd")
@@ -2092,6 +2105,10 @@ class QemuVM(BaseNode):
except OSError as e:
raise QemuError("Cannot copy OVMF_VARS_4M.fd file to the node working directory: {}".format(e))
options.extend(["-drive", "if=pflash,format=raw,file={}".format(ovmf_vars_node_path)])
# edk2 firmware requires a Random Number Generator (RNG) device in order to turn network adapters on
options.extend(["-object", "rng-random,filename=/dev/urandom,id=rng0 "])
options.extend(["-device", "virtio-rng-pci,rng=rng0"])
return options
def _linux_boot_options(self):
+9 -1
View File
@@ -562,7 +562,15 @@ class Controller:
for project in self._projects.values():
if project.auto_open:
await project.open()
try:
await project.open()
except aiohttp.web.HTTPClientError as e:
details = e.text or e.reason or str(e)
log.warning(
"Failed to auto-open project '%s': %s",
project.name,
details,
)
def get_free_project_name(self, base_name):
"""
+12 -5
View File
@@ -271,7 +271,7 @@ async def _upload_file(compute, project_id, file_path, path):
async def _import_images(controller, images_path):
"""
Copy images to the images directory or delete them if they already exists.
Copy images to the images directory or delete them if they already exist.
"""
image_dir = controller.images_path()
@@ -279,12 +279,19 @@ async def _import_images(controller, images_path):
for (dirpath, dirnames, filenames) in os.walk(root, followlinks=False):
for filename in filenames:
path = os.path.join(dirpath, filename)
if os.path.islink(path):
continue
dst = os.path.join(image_dir, os.path.relpath(path, root))
os.makedirs(os.path.dirname(dst), exist_ok=True)
await wait_run_in_executor(shutil.move, path, dst)
if not os.path.exists(dst):
await wait_run_in_executor(shutil.move, path, dst)
try:
with open(dst, "rb") as f:
# read the first 7 bytes of the file.
elf_header_start = f.read(7)
# IOU images must start with the ELF magic number, be 32-bit or 64-bit, little endian and have an ELF version of 1
if elf_header_start == b'\x7fELF\x01\x01\x01' or elf_header_start == b'\x7fELF\x02\x01\x01':
os.chmod(dst, stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC)
except OSError as e:
continue
async def update_snapshots(snapshots_dir, project_path, project_name, project_id, reset_mac_addresses=True):
"""
+48 -1
View File
@@ -905,12 +905,23 @@ class Project:
async def delete(self):
# Check compute connectivity before open() to avoid 120s timeout
# when remote computes are unreachable
disconnected = self._get_disconnected_computes()
if disconnected:
compute_names = ", ".join([f"'{c.name}'" for c in disconnected])
raise aiohttp.web.HTTPForbidden(
f"Cannot delete project '{self.name}': {len(disconnected)} compute(s) are disconnected: {compute_names}. "
f"Please fix the connection or delete the project manually on those computes."
)
if self._status != "opened":
try:
await self.open()
except aiohttp.web.HTTPConflict as e:
# ignore missing images or other conflicts when deleting a project
log.warning("Conflict while deleting project: {}".format(e.text))
log.warning(f"Conflict while deleting project: {e}")
await self.delete_on_computes()
await self.close()
try:
@@ -922,6 +933,42 @@ class Project:
raise aiohttp.web.HTTPConflict(text="Cannot delete project directory {}: {}".format(self.path, str(e)))
self.emit_controller_notification("project.deleted", self.__json__())
def _get_disconnected_computes(self):
"""
Check compute connectivity by reading the topology file directly,
without opening the project (which would try to connect to computes).
Returns a list of disconnected Compute objects.
"""
if self._status == "opened":
# Project is already open, use the already-loaded _computes list
compute_ids = self._computes
else:
# Read compute IDs from topology file without connecting
path = self._topology_file()
if not os.path.exists(path):
return []
try:
project_data = load_topology(path)
except (ValueError, OSError) as e:
log.warning(f"Could not read topology file for project '{self._name}': {e}")
return []
topology = project_data.get("topology", {})
compute_ids = set()
for node in topology.get("nodes", []):
compute_id = node.get("compute_id")
if compute_id:
compute_ids.add(compute_id)
disconnected = []
for compute_id in compute_ids:
try:
compute = self._controller.get_compute(compute_id)
if not compute.connected:
disconnected.append(compute)
except aiohttp.web.HTTPNotFound:
log.warning(f"Compute '{compute_id}' not found in controller")
return disconnected
async def delete_on_computes(self):
"""
Delete the project on computes but not on controller
+1 -1
View File
@@ -57,7 +57,7 @@ class CrashReport:
Report crash to a third party service
"""
DSN = "https://646d66c1f0b65d59af9c4577a68f3f87@o19455.ingest.us.sentry.io/38482"
DSN = "https://deee946d000cb5548acebb1cd7c1a1d3@o19455.ingest.us.sentry.io/38482"
_instance = None
def __init__(self):
+2 -2
View File
@@ -23,8 +23,8 @@
# or negative for a release candidate or beta (after the base version
# number has been incremented)
__version__ = "2.2.60.dev1"
__version_info__ = (2, 2, 60, 99)
__version__ = "2.2.60"
__version_info__ = (2, 2, 60, 0)
if "dev" in __version__:
try: