From d8f8b6ec700fe9c7446eba99ed97b94a6685ad0f Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Fri, 27 Feb 2026 16:35:11 +0100 Subject: [PATCH 1/9] 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'" --- gns3server/compute/docker/__init__.py | 4 ++- gns3server/compute/docker/docker_error.py | 4 +++ gns3server/compute/docker/docker_vm.py | 36 +++++++++++++++++++---- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/gns3server/compute/docker/__init__.py b/gns3server/compute/docker/__init__.py index a441af830..4c12314d5 100644 --- a/gns3server/compute/docker/__init__.py +++ b/gns3server/compute/docker/__init__.py @@ -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 diff --git a/gns3server/compute/docker/docker_error.py b/gns3server/compute/docker/docker_error.py index 5d2b9b1d8..17d45ebbe 100644 --- a/gns3server/compute/docker/docker_error.py +++ b/gns3server/compute/docker/docker_error.py @@ -32,3 +32,7 @@ class DockerHttp304Error(DockerError): class DockerHttp404Error(DockerError): pass + + +class DockerHttp409Error(DockerError): + pass diff --git a/gns3server/compute/docker/docker_vm.py b/gns3server/compute/docker/docker_vm.py index 79b5f640b..7b58305c6 100644 --- a/gns3server/compute/docker/docker_vm.py +++ b/gns3server/compute/docker/docker_vm.py @@ -43,7 +43,8 @@ from ..nios.nio_udp import NIOUDP from .docker_error import ( DockerError, DockerHttp304Error, - DockerHttp404Error + DockerHttp404Error, + DockerHttp409Error ) import logging @@ -459,10 +460,35 @@ 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") + if self._cpus > 0: + log.info(f"CPU limit set to {self._cpus} CPUs") + if self._memory > 0: + log.info(f"Memory limit set to {self._memory} MB") return True def _format_env(self, variables, env): From a58fa8602ba00841aaf006acea25dee89ea60134 Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 13 Jul 2026 10:05:01 +0200 Subject: [PATCH 2/9] remove wrongly merged code --- gns3server/compute/docker/docker_vm.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gns3server/compute/docker/docker_vm.py b/gns3server/compute/docker/docker_vm.py index 7b58305c6..a5822d998 100644 --- a/gns3server/compute/docker/docker_vm.py +++ b/gns3server/compute/docker/docker_vm.py @@ -485,10 +485,6 @@ class DockerVM(BaseNode): raise self._cid = result["Id"] log.info(f"Docker container '{self._name}' [{self._id}] created") - if self._cpus > 0: - log.info(f"CPU limit set to {self._cpus} CPUs") - if self._memory > 0: - log.info(f"Memory limit set to {self._memory} MB") return True def _format_env(self, variables, env): From 896b4fc56a99a13086e229018229b31069b0ba55 Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 13 Jul 2026 11:08:17 +0200 Subject: [PATCH 3/9] UEFI improvements for Qemu VMs * Add OVMF firmware directory configuration * Automatically add a Random Number Generator (RNG) device when using uefi option is enabled --- conf/gns3_server.conf | 2 ++ gns3server/compute/qemu/qemu_vm.py | 21 ++++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/conf/gns3_server.conf b/conf/gns3_server.conf index aa54d57c8..7bb2aa6bd 100644 --- a/conf/gns3_server.conf +++ b/conf/gns3_server.conf @@ -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 diff --git a/gns3server/compute/qemu/qemu_vm.py b/gns3server/compute/qemu/qemu_vm.py index f97e5db31..11399a0ed 100644 --- a/gns3server/compute/qemu/qemu_vm.py +++ b/gns3server/compute/qemu/qemu_vm.py @@ -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,17 @@ 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 + system_ovmf_firmware_path = next(system_ovmf_firmware_dir.glob("OVMF_CODE_4M.fd", case_sensitive=False), 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 +2077,9 @@ 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 + system_ovmf_vars_path = next(system_ovmf_firmware_dir.glob("OVMF_VARS_4M.fd", case_sensitive=False), 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 +2095,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): From 61c7f4469dda6b755b93762e9efe95c63330d97c Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 13 Jul 2026 11:34:29 +0200 Subject: [PATCH 4/9] Search for system UEFI that is compatible with Python < 3.12 --- gns3server/compute/qemu/qemu_vm.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/gns3server/compute/qemu/qemu_vm.py b/gns3server/compute/qemu/qemu_vm.py index 11399a0ed..fa7757a62 100644 --- a/gns3server/compute/qemu/qemu_vm.py +++ b/gns3server/compute/qemu/qemu_vm.py @@ -2066,7 +2066,13 @@ class QemuVM(BaseNode): # 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 = next(system_ovmf_firmware_dir.glob("OVMF_CODE_4M.fd", case_sensitive=False), None) + # 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: @@ -2077,7 +2083,11 @@ 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 = next(system_ovmf_firmware_dir.glob("OVMF_VARS_4M.fd", case_sensitive=False), None) + 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: From c528d2cd950b5eac072f5b499d145ab40c645db9 Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 13 Jul 2026 18:19:52 +0200 Subject: [PATCH 5/9] fix(import): project import does not move images symlinks into place --- gns3server/controller/import_project.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gns3server/controller/import_project.py b/gns3server/controller/import_project.py index a0f95bf00..56d4bb4f5 100644 --- a/gns3server/controller/import_project.py +++ b/gns3server/controller/import_project.py @@ -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,11 +279,12 @@ 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) + if not os.path.islink(dst): + os.chmod(dst, stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC) async def update_snapshots(snapshots_dir, project_path, project_name, project_id, reset_mac_addresses=True): From 1986bce538f4e12f43d8665ccb97dd10564035c0 Mon Sep 17 00:00:00 2001 From: grossmj Date: Wed, 15 Jul 2026 09:43:34 +0200 Subject: [PATCH 6/9] Only set IOU images to be executable when importing images --- gns3server/controller/import_project.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gns3server/controller/import_project.py b/gns3server/controller/import_project.py index 56d4bb4f5..a1912208f 100644 --- a/gns3server/controller/import_project.py +++ b/gns3server/controller/import_project.py @@ -283,9 +283,15 @@ async def _import_images(controller, images_path): os.makedirs(os.path.dirname(dst), exist_ok=True) if not os.path.exists(dst): await wait_run_in_executor(shutil.move, path, dst) - if not os.path.islink(dst): - os.chmod(dst, stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC) - + 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): """ From f088c55cfe8b4e1e5295f39b4dbce54edea78794 Mon Sep 17 00:00:00 2001 From: grossmj Date: Wed, 15 Jul 2026 18:32:12 +0200 Subject: [PATCH 7/9] Sync appliances --- gns3server/appliances/bird.gns3a | 47 ++- gns3server/appliances/fortimanager.gns3a | 490 +--------------------- gns3server/appliances/infix.gns3a | 28 ++ gns3server/appliances/ubuntu-docker.gns3a | 2 +- gns3server/appliances/westermo-weos.gns3a | 14 + 5 files changed, 81 insertions(+), 500 deletions(-) diff --git a/gns3server/appliances/bird.gns3a b/gns3server/appliances/bird.gns3a index b18e18e86..9ecf790cc 100644 --- a/gns3server/appliances/bird.gns3a +++ b/gns3server/appliances/bird.gns3a @@ -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" } } ] diff --git a/gns3server/appliances/fortimanager.gns3a b/gns3server/appliances/fortimanager.gns3a index b5de0248e..ae51af861 100644 --- a/gns3server/appliances/fortimanager.gns3a +++ b/gns3server/appliances/fortimanager.gns3a @@ -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" } } ] diff --git a/gns3server/appliances/infix.gns3a b/gns3server/appliances/infix.gns3a index 736863ba7..481cba0fd 100644 --- a/gns3server/appliances/infix.gns3a +++ b/gns3server/appliances/infix.gns3a @@ -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": { diff --git a/gns3server/appliances/ubuntu-docker.gns3a b/gns3server/appliances/ubuntu-docker.gns3a index 9cde03e79..c69a1405d 100644 --- a/gns3server/appliances/ubuntu-docker.gns3a +++ b/gns3server/appliances/ubuntu-docker.gns3a @@ -14,7 +14,7 @@ "symbol": "linux_guest.svg", "docker": { "adapters": 1, - "image": "gns3/ubuntu:noble", + "image": "gns3/ubuntu:resolute", "console_type": "telnet" } } diff --git a/gns3server/appliances/westermo-weos.gns3a b/gns3server/appliances/westermo-weos.gns3a index 6ebce85d7..dbcf3a7eb 100644 --- a/gns3server/appliances/westermo-weos.gns3a +++ b/gns3server/appliances/westermo-weos.gns3a @@ -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": { From 803cc1741035cd8ae83cfde169baa17356d6714e Mon Sep 17 00:00:00 2001 From: grossmj Date: Wed, 15 Jul 2026 18:36:26 +0200 Subject: [PATCH 8/9] Release v2.2.60 --- CHANGELOG | 14 ++++++++ gns3server/appliances/bird2.gns3a | 57 ------------------------------- gns3server/crash_report.py | 2 +- gns3server/version.py | 4 +-- 4 files changed, 17 insertions(+), 60 deletions(-) delete mode 100644 gns3server/appliances/bird2.gns3a diff --git a/CHANGELOG b/CHANGELOG index 42f09ab17..02d3d14f9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 diff --git a/gns3server/appliances/bird2.gns3a b/gns3server/appliances/bird2.gns3a deleted file mode 100644 index 670d56a83..000000000 --- a/gns3server/appliances/bird2.gns3a +++ /dev/null @@ -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" - } - } - ] -} diff --git a/gns3server/crash_report.py b/gns3server/crash_report.py index 4dce82c80..5b3250a0a 100644 --- a/gns3server/crash_report.py +++ b/gns3server/crash_report.py @@ -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): diff --git a/gns3server/version.py b/gns3server/version.py index 8d4ff1a3f..a384e3124 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -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: From c75e1ba0be5133d9b6a8a65412b8941cc74fcddd Mon Sep 17 00:00:00 2001 From: grossmj Date: Wed, 15 Jul 2026 20:45:33 +0200 Subject: [PATCH 9/9] Development on 2.2.61.dev1 --- gns3server/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gns3server/version.py b/gns3server/version.py index a384e3124..0df2dccb4 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,8 +23,8 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "2.2.60" -__version_info__ = (2, 2, 60, 0) +__version__ = "2.2.61.dev1" +__version_info__ = (2, 2, 61, 99) if "dev" in __version__: try: