Compare commits

..

No commits in common. "master" and "v2.2.58" have entirely different histories.

67 changed files with 840 additions and 1442 deletions

View File

@ -1,57 +0,0 @@
# Version control
.git
.gitignore
.gitattributes
# CI / GitHub / Docker
.github
.whitesource
.dockerignore
# Editor / IDE
.idea
.vscode
.settings
.project
.pydevproject
.mr.developer.cfg
# Claude
.claude
# Python build artifacts
__pycache__
*.py[cod]
*.so
*.egg
*.egg-info
build/
dist/
eggs/
parts/
var/
sdist/
develop-eggs/
.installed.cfg
lib/
lib64/
.ropeproject
# Test & coverage
tests/
pytest.ini
.coveragerc
.coverage
.coverage*
.tox
.cache
.pytest_cache
nosetests.xml
# Virtualenv
env/
venv/
.venv/
# Editor backup files
*~

View File

@ -1,40 +0,0 @@
name: Bug report
description: Report a bug so we can fix it.
title: "[Bug]: "
labels: ["bug"]
body:
- type: textarea
id: what-happened
attributes:
label: What happened?
description: A clear description of the bug.
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce
description: How can we reproduce this? Numbered steps if possible.
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected behavior
description: What did you expect to happen instead?
- type: input
id: version
attributes:
label: Version / commit
description: Which version or commit hash are you on?
- type: textarea
id: environment
attributes:
label: Environment
description: OS, runtime version, anything else that might be relevant.
- type: textarea
id: logs
attributes:
label: Relevant logs
description: Paste any relevant log output. This is automatically rendered as code.
render: shell

View File

@ -10,7 +10,7 @@ jobs:
name: Add issue to project name: Add issue to project
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/add-to-project@v2 - uses: actions/add-to-project@v1.0.1
with: with:
project-url: https://github.com/orgs/GNS3/projects/3 project-url: https://github.com/orgs/GNS3/projects/3
github-token: ${{ secrets.ADD_NEW_ISSUES_TO_PROJECT }} github-token: ${{ secrets.ADD_NEW_ISSUES_TO_PROJECT }}

View File

@ -56,11 +56,11 @@ jobs:
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v7 uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v4 uses: github/codeql-action/init@v3
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }} build-mode: ${{ matrix.build-mode }}
@ -88,6 +88,6 @@ jobs:
exit 1 exit 1
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4 uses: github/codeql-action/analyze@v3
with: with:
category: "/language:${{matrix.language}}" category: "/language:${{matrix.language}}"

View File

@ -10,59 +10,31 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
DOCKERHUB_ORG: ${{ vars.DOCKERHUB_ORG || 'gns3' }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v7 uses: actions/checkout@v4
- name: Check for stable release
id: ver
run: |
TAG="${GITHUB_REF_NAME#v}"
echo "tag=$TAG" >> $GITHUB_OUTPUT
if echo "$TAG" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "stable=true" >> $GITHUB_OUTPUT
else
echo "stable=false" >> $GITHUB_OUTPUT
fi
- name: Set lowercase image name vars
if: steps.ver.outputs.stable == 'true'
id: names
run: |
echo "owner=$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
echo "repo=$(echo '${{ github.event.repository.name }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
- name: Set up Docker Buildx
if: steps.ver.outputs.stable == 'true'
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
if: steps.ver.outputs.stable == 'true' uses: docker/login-action@v3
uses: docker/login-action@v4
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub - name: Login to Docker Hub
if: steps.ver.outputs.stable == 'true' uses: docker/login-action@v3
uses: docker/login-action@v4
with: with:
registry: docker.io registry: docker.io
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push - name: Build and push to GitHub Container Registry
if: steps.ver.outputs.stable == 'true' run: |
uses: docker/build-push-action@v6 docker build -t ghcr.io/$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]'):latest .
with: docker push ghcr.io/$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]'):latest
context: .
push: true - name: Build and push to Docker Hub
tags: | run: |
${{ env.DOCKERHUB_ORG }}/${{ github.event.repository.name }}:${{ steps.ver.outputs.tag }} docker build -t gns3/${{ github.event.repository.name }}:latest .
${{ env.DOCKERHUB_ORG }}/${{ github.event.repository.name }}:latest docker push gns3/${{ github.event.repository.name }}:latest
ghcr.io/${{ steps.names.outputs.owner }}/${{ steps.names.outputs.repo }}:${{ steps.ver.outputs.tag }}
ghcr.io/${{ steps.names.outputs.owner }}/${{ steps.names.outputs.repo }}:latest

View File

@ -12,11 +12,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
ref: "gh-pages" ref: "gh-pages"
- uses: actions/setup-python@v6 - uses: actions/setup-python@v5
with: with:
python-version: 3.8 python-version: 3.8
- name: Merge changes from 3.0 branch - name: Merge changes from 3.0 branch

View File

@ -21,9 +21,9 @@ jobs:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6 uses: actions/setup-python@v5
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
- name: Install dependencies - name: Install dependencies

View File

@ -1,39 +1,5 @@
# Change Log # Change Log
## 2.2.61 30/07/2026
* Sync appliances
* fix(import): unvalidated symlink creation in import_project
* fix(qemu): fix addition of QEMU RNG device causes interface names to change
* fix(qemu): remove trailing space from RNG object argument
* fix: do not start nodes when deleting a project
* fix: correct always-true state check in DockerVM.stop()
## 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
* Fix snapshot restore does not work after export/import of project
* Warn to use 64-bit IOU images. Fixes #2716 32-bit IOU image support has been removed from the GNS3 VM.
* Fix telnet console silent-proxy hang on non-ConnectionError exit (#2344)
## 2.2.58.1 12/04/2026
* Sync appliances
## 2.2.58 10/04/2026 ## 2.2.58 10/04/2026
* Bundle web-ui v2.2.58 * Bundle web-ui v2.2.58

View File

@ -103,8 +103,6 @@ enable_hardware_acceleration = True
require_hardware_acceleration = False require_hardware_acceleration = False
; Allow unsafe additional command line options ; Allow unsafe additional command line options
allow_unsafe_options = False allow_unsafe_options = False
; Path to the OVMF firmware directory
ovmf_firmware_dir = "/usr/share/OVMF"
[VMware] [VMware]
; First vmnet interface of the range that can be managed by the GNS3 server ; First vmnet interface of the range that can be managed by the GNS3 server

View File

@ -1,17 +0,0 @@
curl -i -X 'http://localhost:3080/v2/templates/19021f99-e36f-394d-b4a1-8aaa902ab9cc/base-config/vpcs_base_config.txt'
GET /v2/templates/19021f99-e36f-394d-b4a1-8aaa902ab9cc/base-config/vpcs_base_config.txt HTTP/1.1
HTTP/1.1 200 OK
Connection: close
X-Route: /v2/templates/{template_id}/base-config/{filename}
Server: Python/3.14 GNS3/2.2.60.dev1+713dbb7f
Content-Type: application/json
Content-Length: 144
Date: Mon, 18 May 2026 18:34:10 GMT
{
"content": "# test config\n\ndhcp\n",
"filename": "vpcs_base_config.txt",
"template_id": "19021f99-e36f-394d-b4a1-8aaa902ab9cc"
}

View File

@ -1,44 +0,0 @@
curl -i -X 'http://localhost:3080/v2/templates/base-configs'
GET /v2/templates/base-configs HTTP/1.1
HTTP/1.1 200 OK
Connection: close
X-Route: /v2/templates/base-configs
Server: Python/3.14 GNS3/2.2.60.dev1+713dbb7f
Content-Type: application/json
Content-Length: 576
Date: Mon, 18 May 2026 18:28:53 GMT
[
{
"filename": "config1.txt"
},
{
"filename": "config2.txt"
},
{
"filename": "ios_base_startup-config.txt"
},
{
"filename": "ios_etherswitch_startup-config.txt"
},
{
"filename": "iou_l2_base_startup-config.txt"
},
{
"filename": "iou_l3_base_startup-config.txt"
},
{
"filename": "test_config.txt"
},
{
"filename": "update_test.txt"
},
{
"filename": "vpcs_base_config.txt"
},
{
"filename": "vpcs_base_config2.txt"
}
]

View File

@ -1,17 +0,0 @@
curl -i -X 'http://localhost:3080/v2/templates/19021f99-e36f-394d-b4a1-8aaa902ab9cc/base-config/vpcs_base_config.txt'
PUT /v2/templates/19021f99-e36f-394d-b4a1-8aaa902ab9cc/base-config/vpcs_base_config.txt HTTP/1.1
HTTP/1.1 200 OK
Connection: close
X-Route: /v2/templates/{template_id}/base-config/{filename}
Server: Python/3.14 GNS3/2.2.60.dev1+713dbb7f
Content-Type: application/json
Content-Length: 144
Date: Mon, 18 May 2026 18:37:57 GMT
{
"content": "# test config\n\ndhcp\n",
"filename": "vpcs_base_config.txt",
"template_id": "19021f99-e36f-394d-b4a1-8aaa902ab9cc"
}

View File

@ -1,38 +0,0 @@
GET /v2/templates/base-configs
------------------------------------------------------------------------------------------------------------------------------------------
.. contents::
GET /v2/templates/base-configs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
List all available base configuration files
Response status codes
**********************
- **200**: List of base configuration files returned
Output
*******
.. raw:: html
<table>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr>
<td>filename</td>
<td>string</td>
<td>Name of the base configuration file</td>
</tr>
</table>
Sample session
***************
.. literalinclude:: ../../../examples/controller_get_templatesbaseconfigs.txt

View File

@ -1,90 +0,0 @@
/v2/templates/{template_id}/base-config/{filename}
------------------------------------------------------------------------------------------------------------------------------------------
.. contents::
GET /v2/templates/**{template_id}**/base-configs/**{filename}**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
List all available base configuration files
Response status codes
**********************
- **200**: List of base configuration files returned
Output
*******
.. raw:: html
<table>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr>
<td>filename</td>
<td>string</td>
<td>Name of the base configuration file</td>
</tr>
</table>
Sample session
***************
.. literalinclude:: ../../../examples/controller_get_templateidbaseconfig.txt
PUT /v2/templates/**{template_id}**/base-config/**{filename}**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Update base configuration file content
Response status codes
**********************
- **200**: File updated
- **404**: File not found
Input
*******
.. raw:: html
<table>
<tr>
<th>Name</th>
<th>Mandatory</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr><td>content</td><td>&#10004;</td><td>string</td><td>New file content</td></tr>
</table>
Output
*******
.. raw:: html
<table>
<tr>
<th>Name</th>
<th>Mandatory</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr><td>template_id</td><td>&#10004;</td><td>string</td><td>Template UUID</td></tr>
<tr><td>filename</td><td>&#10004;</td><td>string</td><td>Base configuration filename</td></tr>
<tr><td>content</td><td>&#10004;</td><td>string</td><td>Updated file content</td></tr>
</table>
Sample session
***************
.. literalinclude:: ../../../examples/controller_put_templateidbaseconfig.txt

View File

@ -25,30 +25,6 @@
"options": "-cpu host -nographic" "options": "-cpu host -nographic"
}, },
"images": [ "images": [
{
"filename": "AlmaLinux-10-GenericCloud-10.0-20250528.0.x86_64.qcow2",
"version": "10.0",
"md5sum": "e5099e33f16014b6cc851482d865720d",
"filesize": 460062720,
"download_url": "https://vault.almalinux.org/10.0/cloud/x86_64/images/",
"direct_download_url": "https://vault.almalinux.org/10.0/cloud/x86_64/images/AlmaLinux-10-GenericCloud-10.0-20250528.0.x86_64.qcow2"
},
{
"filename": "AlmaLinux-9-GenericCloud-9.6-20250522.x86_64.qcow2",
"version": "9.6",
"md5sum": "ae02074389961caf08bbe44439603061",
"filesize": 530776064,
"download_url": "https://vault.almalinux.org/9.6/cloud/x86_64/images/",
"direct_download_url": "https://vault.almalinux.org/9.6/cloud/x86_64/images/AlmaLinux-9-GenericCloud-9.6-20250522.x86_64.qcow2"
},
{
"filename": "AlmaLinux-9-GenericCloud-9.5-20241120.x86_64.qcow2",
"version": "9.5",
"md5sum": "cb48bc1c609a1d3d62f48397acdd038e",
"filesize": 490995712,
"download_url": "https://vault.almalinux.org/9.5/cloud/x86_64/images/",
"direct_download_url": "https://vault.almalinux.org/9.5/cloud/x86_64/images/AlmaLinux-9-GenericCloud-9.5-20241120.x86_64"
},
{ {
"filename": "AlmaLinux-9-GenericCloud-9.4-20240805.x86_64.qcow2", "filename": "AlmaLinux-9-GenericCloud-9.4-20240805.x86_64.qcow2",
"version": "9.4", "version": "9.4",
@ -99,27 +75,6 @@
} }
], ],
"versions": [ "versions": [
{
"name": "10.0",
"images": {
"hda_disk_image": "AlmaLinux-10-GenericCloud-10.0-20250528.0.x86_64.qcow2",
"cdrom_image": "almalinux-cloud-init-data.iso"
}
},
{
"name": "9.6",
"images": {
"hda_disk_image": "AlmaLinux-9-GenericCloud-9.6-20250522.x86_64.qcow2",
"cdrom_image": "almalinux-cloud-init-data.iso"
}
},
{
"name": "9.5",
"images": {
"hda_disk_image": "AlmaLinux-9-GenericCloud-9.5-20241120.x86_64.qcow2",
"cdrom_image": "almalinux-cloud-init-data.iso"
}
},
{ {
"name": "9.4", "name": "9.4",
"images": { "images": {

View File

@ -1,59 +0,0 @@
{
"appliance_id": "b3b90fde-143a-4129-8031-ccbba73c5e02",
"name": "armbian",
"category": "guest",
"description": "A highly optimized base operating system specialized for single board computers (SBCs) and its extensive build framework.",
"vendor_name": "The Armbian team",
"vendor_url": "https://armbian.com/",
"documentation_url": "https://docs.armbian.com/",
"product_name": "Armbian UEFI x86",
"product_url": "https://armbian.com/boards/uefi-x86",
"registry_version": 4,
"status": "stable",
"maintainer": "GNS3 Team",
"maintainer_email": "developers@gns3.net",
"usage": "By first login you create root password and new sudo user.\n\nBoot disk from UEFI shell, type: FS0:EFI\\BOOT\\BOOTX64 and press <Enter>",
"port_name_format": "Ethernet{0}",
"qemu": {
"adapter_type": "virtio-net-pci",
"adapters": 2,
"ram": 256,
"hda_disk_interface": "virtio",
"arch": "x86_64",
"console_type": "spice+agent",
"uefi": false,
"boot_priority": "c",
"kvm": "require",
"options": "-nographic"
},
"images": [
{
"filename": "OVMF-edk2-stable202305.fd",
"version": "stable202305",
"md5sum": "6c4cf1519fec4a4b95525d9ae562963a",
"filesize": 4194304,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/OVMF-edk2-stable202305.fd.zip/download",
"compression": "zip"
},
{
"filename": "Armbian_26.5.1_Uefi-x86_trixie_cloud_6.18.32_minimal.img.qcow2",
"version": "Armbian 26.5.1 Minimal (CLI)",
"md5sum": "7f4c915668718d6135406de5a6c4fc30",
"filesize": 877920512,
"download_url": "https://armbian.com/boards/uefi-x86",
"direct_download_url": "https://armbian.atomonetworks.com/dl/uefi-x86/archive/Armbian_26.5.1_Uefi-x86_trixie_cloud_6.18.32_minimal.img.qcow2.xz",
"compression": "xz"
}
],
"versions": [
{
"name": "Armbian 26.5.1 Minimal (CLI)",
"images": {
"bios_image": "OVMF-edk2-stable202305.fd",
"hda_disk_image": "Armbian_26.5.1_Uefi-x86_trixie_cloud_6.18.32_minimal.img.qcow2"
}
}
]
}

View File

@ -1,56 +1,41 @@
{ {
"appliance_id": "8fecbf89-5cd1-4aea-b735-5f36cf0efbb7", "appliance_id": "088df570-f637-46f5-8a68-85acde538e5e",
"name": "BIRD", "name": "BIRD",
"category": "router", "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.", "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_name": "CZ.NIC Labs",
"vendor_url": "https://bird.network.cz", "vendor_url": "http://bird.network.cz/",
"documentation_url": "https://bird.network.cz/?get_doc&f=bird.html&v=20", "documentation_url": "http://bird.network.cz/?get_doc&f=bird.html",
"product_name": "BIRD internet routing daemon", "product_name": "BIRD internet routing daemon",
"registry_version": 4, "registry_version": 4,
"status": "stable", "status": "stable",
"maintainer": "Bernhard Ehlers", "maintainer": "GNS3 Team",
"maintainer_email": "dev-ehlers@mailbox.org", "maintainer_email": "developers@gns3.net",
"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", "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",
"port_name_format": "eth{0}",
"qemu": { "qemu": {
"adapter_type": "virtio-net-pci", "adapter_type": "e1000",
"adapters": 4, "adapters": 4,
"ram": 512, "ram": 128,
"hda_disk_interface": "scsi", "hda_disk_interface": "ide",
"arch": "x86_64", "arch": "x86_64",
"console_type": "telnet", "console_type": "telnet",
"kvm": "allow" "kvm": "allow"
}, },
"images": [ "images": [
{ {
"filename": "bird2-debian-2.14.qcow2", "filename": "bird-tinycore64-1.5.0.img",
"version": "2.14", "version": "1.5.0",
"md5sum": "029cf1756201ee79497c169502b08b88", "md5sum": "08d50ba2b1b262e2e03e4babf90abf69",
"filesize": 303717376, "filesize": 22413312,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/", "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" "direct_download_url": "http://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/bird-tinycore64-1.5.0.img"
},
{
"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": [ "versions": [
{ {
"name": "2.14", "name": "1.5.0",
"images": { "images": {
"hda_disk_image": "bird2-debian-2.14.qcow2" "hda_disk_image": "bird-tinycore64-1.5.0.img"
}
},
{
"name": "2.0.12",
"images": {
"hda_disk_image": "bird2-debian-2.0.12.qcow2"
} }
} }
] ]

View File

@ -0,0 +1,57 @@
{
"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"
}
}
]
}

View File

@ -27,20 +27,20 @@
}, },
"images": [ "images": [
{ {
"filename": "CentOS-Stream-GenericCloud-10-20260504.0.x86_64.qcow2", "filename": "CentOS-Stream-GenericCloud-x86_64-10-20250331.0.x86_64.qcow2",
"version": "Stream-10 (20260504.0)", "version": "Stream-10 (20250331.0)",
"md5sum": "932b0bcc7e5c7404f91432979dc95314", "md5sum": "776033371ca346001dd6390f0cbaf0d0",
"filesize": 2173501440, "filesize": 952041472,
"download_url": "https://cloud.centos.org/centos/10-stream/x86_64/images", "download_url": "https://cloud.centos.org/centos/10-stream/x86_64/images",
"direct_download_url": "https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-10-20260504.0.x86_64.qcow2" "direct_download_url": "https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-10-20250331.0.x86_64.qcow2"
}, },
{ {
"filename": "CentOS-Stream-GenericCloud-9-20260504.0.x86_64.qcow2", "filename": "CentOS-Stream-GenericCloud-9-20250331.0.x86_64.qcow2",
"version": "Stream-9 (20260504.0)", "version": "Stream-9 (20250331.0)",
"md5sum": "ebfbbd23ba7b85bbaf83c6c0626c2b70", "md5sum": "4aaeddc6ca497065522c75a7471f9bfd",
"filesize": 1877251072, "filesize": 1250625536,
"download_url": "https://cloud.centos.org/centos/9-stream/x86_64/images", "download_url": "https://cloud.centos.org/centos/9-stream/x86_64/images",
"direct_download_url": "https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-9-20260504.0.x86_64.qcow2" "direct_download_url": "https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-9-20250331.0.x86_64.qcow2"
}, },
{ {
"filename": "CentOS-Stream-GenericCloud-8-20240603.0.x86_64.qcow2", "filename": "CentOS-Stream-GenericCloud-8-20240603.0.x86_64.qcow2",
@ -61,16 +61,16 @@
], ],
"versions": [ "versions": [
{ {
"name": "Stream-10 (20260504.0)", "name": "Stream-10 (20250331.0)",
"images": { "images": {
"hda_disk_image": "CentOS-Stream-GenericCloud-10-20260504.0.x86_64.qcow2", "hda_disk_image": "CentOS-Stream-GenericCloud-x86_64-10-20250331.0.x86_64.qcow2",
"cdrom_image": "centos-cloud-init-data.iso" "cdrom_image": "centos-cloud-init-data.iso"
} }
}, },
{ {
"name": "Stream-9 (20260504.0)", "name": "Stream-9 (20250331.0)",
"images": { "images": {
"hda_disk_image": "CentOS-Stream-GenericCloud-9-20260504.0.x86_64.qcow2", "hda_disk_image": "CentOS-Stream-GenericCloud-9-20250331.0.x86_64.qcow2",
"cdrom_image": "centos-cloud-init-data.iso" "cdrom_image": "centos-cloud-init-data.iso"
} }
}, },

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "cc2b1802-3520-4963-8ff7-c19b1f6418c5", "appliance_id": "cc2b1802-3520-4963-8ff7-c19b1f6418c5",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco 1700", "name": "Cisco 1700",
"category": "router", "category": "router",
"description": "Cisco 1700 Router", "description": "Cisco 1700 Router",

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "ed474fea-cd3b-4e2e-be84-a855a133060a", "appliance_id": "ed474fea-cd3b-4e2e-be84-a855a133060a",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco 2600", "name": "Cisco 2600",
"category": "router", "category": "router",
"description": "Cisco 2600 Router", "description": "Cisco 2600 Router",

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "ed0f079e-a506-4cb4-b46c-714a80bbe2d3", "appliance_id": "ed0f079e-a506-4cb4-b46c-714a80bbe2d3",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco 2691", "name": "Cisco 2691",
"category": "router", "category": "router",
"description": "Cisco 2691 Router", "description": "Cisco 2691 Router",

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "7ada6336-7280-4306-9f32-6b1e242ae989", "appliance_id": "7ada6336-7280-4306-9f32-6b1e242ae989",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco 3620", "name": "Cisco 3620",
"category": "router", "category": "router",
"description": "Cisco 3620 Router", "description": "Cisco 3620 Router",

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "ef119e49-19fe-4239-9c6b-16ea12f6ec01", "appliance_id": "ef119e49-19fe-4239-9c6b-16ea12f6ec01",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco 3640", "name": "Cisco 3640",
"category": "router", "category": "router",
"description": "Cisco 3640 Router", "description": "Cisco 3640 Router",

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "ac460a9c-9274-4ccf-a056-af50b699925f", "appliance_id": "ac460a9c-9274-4ccf-a056-af50b699925f",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco 3660", "name": "Cisco 3660",
"category": "router", "category": "router",
"description": "Cisco 3660 Router", "description": "Cisco 3660 Router",

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "5b9c5293-a5a7-47a3-9df4-6cf658f2f378", "appliance_id": "5b9c5293-a5a7-47a3-9df4-6cf658f2f378",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco 3725", "name": "Cisco 3725",
"category": "router", "category": "router",
"description": "Cisco 3725 Router", "description": "Cisco 3725 Router",

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "18737edb-e43f-4fb0-8a0f-88982cff58b1", "appliance_id": "18737edb-e43f-4fb0-8a0f-88982cff58b1",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco 3745", "name": "Cisco 3745",
"category": "router", "category": "router",
"description": "Cisco 3745 Multiservice Access Router", "description": "Cisco 3745 Multiservice Access Router",

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "38aa3135-f169-4131-9b64-73605787b5ef", "appliance_id": "38aa3135-f169-4131-9b64-73605787b5ef",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco 7200", "name": "Cisco 7200",
"category": "router", "category": "router",
"description": "Cisco 7200 Router", "description": "Cisco 7200 Router",

View File

@ -9,7 +9,7 @@
"product_name": "Alpine Linux Virt", "product_name": "Alpine Linux Virt",
"product_url": "https://developer.cisco.com/modeling-labs/", "product_url": "https://developer.cisco.com/modeling-labs/",
"registry_version": 4, "registry_version": 4,
"status": "experimental", "status": "beta",
"maintainer": "GNS3 Team", "maintainer": "GNS3 Team",
"maintainer_email": "developers@gns3.net", "maintainer_email": "developers@gns3.net",
"usage": "By default, a \"cisco\" account with password \"cisco\" is created.", "usage": "By default, a \"cisco\" account with password \"cisco\" is created.",

View File

@ -26,13 +26,6 @@
"kvm": "require" "kvm": "require"
}, },
"images": [ "images": [
{
"filename": "asav9-23-1.qcow2",
"version": "9.23.1 CML",
"md5sum": "30454794b46fe07d1cd6a3ee72b511e1",
"filesize": 400687104,
"download_url": "https://u.cisco.com/my-learning/my-account"
},
{ {
"filename": "asav9-22-1-1.qcow2", "filename": "asav9-22-1-1.qcow2",
"version": "9.22.1.1 CML", "version": "9.22.1.1 CML",
@ -140,12 +133,6 @@
} }
], ],
"versions": [ "versions": [
{
"name": "9.23.1 CML",
"images": {
"hda_disk_image": "asav9-23-1.qcow2"
}
},
{ {
"name": "9.22.1.1 CML", "name": "9.22.1.1 CML",
"images": { "images": {

View File

@ -17,7 +17,7 @@
"qemu": { "qemu": {
"adapter_type": "vmxnet3", "adapter_type": "vmxnet3",
"adapters": 4, "adapters": 4,
"ram": 4096, "ram": 3072,
"hda_disk_interface": "ide", "hda_disk_interface": "ide",
"arch": "x86_64", "arch": "x86_64",
"console_type": "telnet", "console_type": "telnet",

View File

@ -1,12 +1,11 @@
{ {
"appliance_id": "3bf492b6-5717-4257-9bfd-b34617c6f133", "appliance_id": "3bf492b6-5717-4257-9bfd-b34617c6f133",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco IOSv", "name": "Cisco IOSv",
"category": "router", "category": "router",
"description": "Cisco Virtual IOS allows user to run IOS on a standard computer.", "description": "Cisco Virtual IOS allows user to run IOS on a standard computer.",
"vendor_name": "Cisco", "vendor_name": "Cisco",
"vendor_url": "http://www.cisco.com/", "vendor_url": "http://www.cisco.com/",
"documentation_url": "https://developer.cisco.com/docs/modeling-labs/iosv/", "documentation_url": "https://developer.cisco.com/docs/modeling-labs/iol/",
"product_name": "IOSv", "product_name": "IOSv",
"product_url": "https://developer.cisco.com/modeling-labs/", "product_url": "https://developer.cisco.com/modeling-labs/",
"registry_version": 4, "registry_version": 4,
@ -26,13 +25,6 @@
"kvm": "require" "kvm": "require"
}, },
"images": [ "images": [
{
"filename": "vios-adventerprisek9-m.spa.159-3.m10.qcow2",
"version": "15.9(3)M10",
"md5sum": "960ff630ce3fc030f6155a8e77d64105",
"filesize": 57323520,
"download_url": "https://u.cisco.com/my-learning/my-account"
},
{ {
"filename": "vios-adventerprisek9-m.spa.159-3.m9.qcow2", "filename": "vios-adventerprisek9-m.spa.159-3.m9.qcow2",
"version": "15.9(3)M9", "version": "15.9(3)M9",
@ -120,13 +112,6 @@
} }
], ],
"versions": [ "versions": [
{
"name": "15.9(3)M10",
"images": {
"hda_disk_image": "vios-adventerprisek9-m.spa.159-3.m10.qcow2",
"hdb_disk_image": "IOSv_startup_config.img"
}
},
{ {
"name": "15.9(3)M9", "name": "15.9(3)M9",
"images": { "images": {

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "4368f802-ddec-4863-adbd-a36a6d83cd4c", "appliance_id": "4368f802-ddec-4863-adbd-a36a6d83cd4c",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco IOSvL2", "name": "Cisco IOSvL2",
"category": "multilayer_switch", "category": "multilayer_switch",
"description": "Cisco Virtual IOS L2 allows user to run a IOS switching image on a standard computer.", "description": "Cisco Virtual IOS L2 allows user to run a IOS switching image on a standard computer.",

View File

@ -19,21 +19,13 @@
"adapter_type": "virtio-net-pci", "adapter_type": "virtio-net-pci",
"adapters": 7, "adapters": 7,
"ram": 16384, "ram": 16384,
"cpus": 4,
"hda_disk_interface": "ide", "hda_disk_interface": "ide",
"arch": "x86_64", "arch": "x86_64",
"console_type": "telnet", "console_type": "telnet",
"kvm": "require", "kvm": "require",
"options": "-cpu host" "options": "-smp 4 -cpu host"
}, },
"images": [ "images": [
{
"filename": "xrv9k-fullk9-x-25.1.1.qcow2",
"version": "25.1.1",
"md5sum": "554d795d495badf90b6c75a2a342b409",
"filesize": 2002911232,
"download_url": "https://u.cisco.com/my-learning/my-account"
},
{ {
"filename": "xrv9k-fullk9-x-24.3.1.qcow2", "filename": "xrv9k-fullk9-x-24.3.1.qcow2",
"version": "24.3.1", "version": "24.3.1",
@ -57,12 +49,6 @@
} }
], ],
"versions": [ "versions": [
{
"name": "25.1.1",
"images": {
"hda_disk_image": "xrv9k-fullk9-x-25.1.1.qcow2"
}
},
{ {
"name": "24.3.1", "name": "24.3.1",
"images": { "images": {

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "9593db48-558a-4914-bb78-a20605f39c65", "appliance_id": "9593db48-558a-4914-bb78-a20605f39c65",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco IOU L2", "name": "Cisco IOU L2",
"category": "multilayer_switch", "category": "multilayer_switch",
"description": "Cisco IOS on UNIX Layer 2 image.", "description": "Cisco IOS on UNIX Layer 2 image.",
@ -38,6 +37,18 @@
"version": "17.12.1", "version": "17.12.1",
"md5sum": "2b5055e4cef8fd257416d74a94adb626", "md5sum": "2b5055e4cef8fd257416d74a94adb626",
"filesize": 240355720 "filesize": 240355720
},
{
"filename": "i86bi_linux_l2-adventerprisek9-ms.SSA.high_iron_20190423.bin",
"version": "15.2(20190423)",
"md5sum": "ffe884f8e762b762d7886c51d8ee015c",
"filesize": 126249700
},
{
"filename": "i86bi_LinuxL2-AdvEnterpriseK9-M_152_May_2018.bin",
"version": "15.2(20180510)",
"md5sum": "d704b68c5f4c4f92e56b754b49b92012",
"filesize": 126226692
} }
], ],
"versions": [ "versions": [
@ -58,6 +69,18 @@
"images": { "images": {
"image": "x86_64_crb_linux_l2-adventerprisek9-ms" "image": "x86_64_crb_linux_l2-adventerprisek9-ms"
} }
},
{
"name": "15.2(20190423)",
"images": {
"image": "i86bi_linux_l2-adventerprisek9-ms.SSA.high_iron_20190423.bin"
}
},
{
"name": "15.2(20180510)",
"images": {
"image": "i86bi_LinuxL2-AdvEnterpriseK9-M_152_May_2018.bin"
}
} }
] ]
} }

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "87bf6f58-1e5a-4ee2-afe7-715dabffcf18", "appliance_id": "87bf6f58-1e5a-4ee2-afe7-715dabffcf18",
"tags": ["device_type:cisco_ios_telnet"],
"name": "Cisco IOU L3", "name": "Cisco IOU L3",
"category": "router", "category": "router",
"description": "Cisco IOS on UNIX Layer 3 image.", "description": "Cisco IOS on UNIX Layer 3 image.",
@ -38,6 +37,12 @@
"version": "17.12.1", "version": "17.12.1",
"md5sum": "4a2fce8de21d1831fbceffd155e41ae7", "md5sum": "4a2fce8de21d1831fbceffd155e41ae7",
"filesize": 288947184 "filesize": 288947184
},
{
"filename": "i86bi_LinuxL3-AdvEnterpriseK9-M2_157_3_May_2018.bin",
"version": "15.7(3)M2",
"md5sum": "d6874260c3daeeb96d10fc844ae0b93b",
"filesize": 184759244
} }
], ],
"versions": [ "versions": [
@ -58,6 +63,12 @@
"images": { "images": {
"image": "x86_64_crb_linux-adventerprisek9-ms" "image": "x86_64_crb_linux-adventerprisek9-ms"
} }
},
{
"name": "15.7(3)M2",
"images": {
"image": "i86bi_LinuxL3-AdvEnterpriseK9-M2_157_3_May_2018.bin"
}
} }
] ]
} }

View File

@ -1,69 +0,0 @@
{
"appliance_id": "4c7fd5da-be86-4168-8484-7071dc9c71fb",
"name": "Cisco NX-OSv 9000 Lite",
"category": "multilayer_switch",
"description": "The NX-OSv 9000 is a virtual platform that is designed to simulate the control plane aspects of a network element running Cisco Nexus 9000 software. The NX-OSv 9000 shares the same software image running on Cisco Nexus 9000 hardware platform although no specific hardware emulation is implemented. When the software runs as a virtual machine, line card (LC) ASIC provisioning or any interaction from the control plane to hardware ASIC is handled by the NX-OSv 9000 software data plane.\nThe NX-OSv 9000 for the Cisco Nexus 9000 Series provides a useful tool to enable the devops model and rapidly test changes to the infrastructure or to infrastructure automation tools. This enables network simulations in large scale for customers to validate configuration changes on a simulated network prior to applying them on a production network. Some users have also expressed interest in using the simulation system for feature test ,verification, and automation tooling development and test simualtion prior to deployment. NX-OSv 9000 can be used as a programmability vehicle to validate software defined networks (SDNs) and Network Function Virtualization (NFV) based solutions.\nThe lite version has a reduced memory footprint, resulting in a much smaller image size than the earlier images for Cisco Nexus 9300v and 9500v.",
"vendor_name": "Cisco",
"vendor_url": "http://www.cisco.com/",
"documentation_url": "https://developer.cisco.com/docs/modeling-labs/nx-os-9000/",
"product_name": "NX-OSv 9000",
"product_url": "https://developer.cisco.com/modeling-labs/",
"registry_version": 4,
"status": "stable",
"availability": "service-contract",
"maintainer": "GNS3 Team",
"maintainer_email": "developers@gns3.net",
"first_port_name": "mgmt0",
"port_name_format": "Ethernet1/{port1}",
"qemu": {
"adapter_type": "e1000",
"adapters": 10,
"ram": 6144,
"cpus": 2,
"hda_disk_interface": "sata",
"arch": "x86_64",
"console_type": "telnet",
"kvm": "require"
},
"images": [
{
"filename": "nexus9500v64-lite.10.5.5.M.qcow2",
"version": "9500v lite 10.5.5.M",
"md5sum": "a9aafd88f36a7f44a5a2ef3322cd9bde",
"filesize": 2617638912,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/10.5(5)"
},
{
"filename": "nexus9300v64-lite.10.5.5.M.qcow2",
"version": "9300v lite 10.5.5.M",
"md5sum": "78610953005faab9505252baf4c86b78",
"filesize": 2617573376,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/10.5(5)"
},
{
"filename": "OVMF-edk2-stable202305.fd",
"version": "stable202305",
"md5sum": "6c4cf1519fec4a4b95525d9ae562963a",
"filesize": 4194304,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/OVMF-edk2-stable202305.fd.zip/download",
"compression": "zip"
}
],
"versions": [
{
"name": "9500v lite 10.5.5.M",
"images": {
"bios_image": "OVMF-edk2-stable202305.fd",
"hda_disk_image": "nexus9500v64-lite.10.5.5.M.qcow2"
}
},
{
"name": "9300v lite 10.5.5.M",
"images": {
"bios_image": "OVMF-edk2-stable202305.fd",
"hda_disk_image": "nexus9300v64-lite.10.5.5.M.qcow2"
}
}
]
}

View File

@ -27,20 +27,6 @@
"kvm": "require" "kvm": "require"
}, },
"images": [ "images": [
{
"filename": "nexus9500v64.10.5.5.M.qcow2",
"version": "9500v 10.5.5.M",
"md5sum": "c1d34bb3331d958d3219a56b6885150e",
"filesize": 2919170048,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/10.5(5)"
},
{
"filename": "nexus9300v64.10.5.5.M.qcow2",
"version": "9300v 10.5.5.M",
"md5sum": "f1cc2342b920320654d232b68551ccfd",
"filesize": 2919104512,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/10.5(5)"
},
{ {
"filename": "nexus9500v64.10.5.1.F.qcow2", "filename": "nexus9500v64.10.5.1.F.qcow2",
"version": "9500v 10.5.1.F", "version": "9500v 10.5.1.F",
@ -94,20 +80,6 @@
} }
], ],
"versions": [ "versions": [
{
"name": "9500v 10.5.5.M",
"images": {
"bios_image": "OVMF-edk2-stable202305.fd",
"hda_disk_image": "nexus9500v64.10.5.5.M.qcow2"
}
},
{
"name": "9300v 10.5.5.M",
"images": {
"bios_image": "OVMF-edk2-stable202305.fd",
"hda_disk_image": "nexus9300v64.10.5.5.M.qcow2"
}
},
{ {
"name": "9500v 10.5.1.F", "name": "9500v 10.5.1.F",
"images": { "images": {

View File

@ -26,30 +26,6 @@
"options": "-nographic" "options": "-nographic"
}, },
"images": [ "images": [
{
"filename": "Fedora-Cloud-Base-Generic-44-1.7.x86_64.qcow2",
"version": "44-1.7",
"md5sum": "49784011eb752291bfead24d3be8163f",
"filesize": 583729152,
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/44/Cloud/x86_64/images",
"direct_download_url": "https://fedora.mirrorservice.org/fedora/linux/releases/44/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-44-1.7.x86_64.qcow2"
},
{
"filename": "Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2",
"version": "43-1.6",
"md5sum": "f2f671db53fae58b79bb2e2259fa3622",
"filesize": 583335936,
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/43/Cloud/x86_64/images",
"direct_download_url": "https://fedora.mirrorservice.org/fedora/linux/releases/43/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2"
},
{
"filename": "Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2",
"version": "42-1.1",
"md5sum": "2d660d2adc20b1fe793df5cb66f1d868",
"filesize": 532217856,
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/42/Cloud/x86_64/images",
"direct_download_url": "https://fedora.mirrorservice.org/fedora/linux/releases/42/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2"
},
{ {
"filename": "Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2", "filename": "Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2",
"version": "41-1.4", "version": "41-1.4",
@ -58,6 +34,30 @@
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/41/Cloud/x86_64/images", "download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/41/Cloud/x86_64/images",
"direct_download_url": "https://fedora.mirrorservice.org/fedora/linux/releases/41/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2" "direct_download_url": "https://fedora.mirrorservice.org/fedora/linux/releases/41/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2"
}, },
{
"filename": "Fedora-Cloud-Base-Generic.x86_64-40-1.14.qcow2",
"version": "40-1.14",
"md5sum": "3eed4b1a9de35208ed30d9bb72c1522d",
"filesize": 397475840,
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/40/Cloud/x86_64/images",
"direct_download_url": "https://fedora.mirrorservice.org/fedora/linux/releases/40/Cloud/x86_64/images/Fedora-Cloud-Base-Generic.x86_64-40-1.14.qcow2"
},
{
"filename": "Fedora-Cloud-Base-39-1.5.x86_64.qcow2",
"version": "39-1.5",
"md5sum": "800a10df2d369891ed65900bcacacd47",
"filesize": 544604160,
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/39/Cloud/x86_64/images",
"direct_download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/39/Cloud/x86_64/images/Fedora-Cloud-Base-39-1.5.x86_64.qcow2"
},
{
"filename": "Fedora-Cloud-Base-38-1.6.x86_64.qcow2",
"version": "38-1.6",
"md5sum": "53ddfe7b28666d5ddc55e93ff06abad2",
"filesize": 497287168,
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/38/Cloud/x86_64/images",
"direct_download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/38/Cloud/x86_64/images/Fedora-Cloud-Base-38-1.6.x86_64.qcow2"
},
{ {
"filename": "fedora-cloud-init-data.iso", "filename": "fedora-cloud-init-data.iso",
"version": "1.0", "version": "1.0",
@ -68,33 +68,33 @@
} }
], ],
"versions": [ "versions": [
{
"name": "44-1.7",
"images": {
"hda_disk_image": "Fedora-Cloud-Base-Generic-44-1.7.x86_64.qcow2",
"cdrom_image": "fedora-cloud-init-data.iso"
}
},
{
"name": "43-1.6",
"images": {
"hda_disk_image": "Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2",
"cdrom_image": "fedora-cloud-init-data.iso"
}
},
{
"name": "42-1.1",
"images": {
"hda_disk_image": "Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2",
"cdrom_image": "fedora-cloud-init-data.iso"
}
},
{ {
"name": "41-1.4", "name": "41-1.4",
"images": { "images": {
"hda_disk_image": "Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2", "hda_disk_image": "Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2",
"cdrom_image": "fedora-cloud-init-data.iso" "cdrom_image": "fedora-cloud-init-data.iso"
} }
},
{
"name": "40-1.14",
"images": {
"hda_disk_image": "Fedora-Cloud-Base-Generic.x86_64-40-1.14.qcow2",
"cdrom_image": "fedora-cloud-init-data.iso"
}
},
{
"name": "39-1.5",
"images": {
"hda_disk_image": "Fedora-Cloud-Base-39-1.5.x86_64.qcow2",
"cdrom_image": "fedora-cloud-init-data.iso"
}
},
{
"name": "38-1.6",
"images": {
"hda_disk_image": "Fedora-Cloud-Base-38-1.6.x86_64.qcow2",
"cdrom_image": "fedora-cloud-init-data.iso"
}
} }
] ]
} }

View File

@ -51,12 +51,250 @@
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx" "download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
}, },
{ {
"filename": "empty500G.qcow2", "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",
"version": "1.0", "version": "1.0",
"md5sum": "658c825441b9b3080ba00f9eec002eaa", "md5sum": "3411a599e822f2ac6be560a26405821a",
"filesize": 204608, "filesize": 197120,
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/", "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/empty500G.qcow2/download" "direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty30G.qcow2/download"
} }
], ],
"versions": [ "versions": [
@ -64,21 +302,259 @@
"name": "7.4.6", "name": "7.4.6",
"images": { "images": {
"hda_disk_image": "FMG_VM64_KVM-v7.4.6.M-build2588-FORTINET.out.kvm.qcow2", "hda_disk_image": "FMG_VM64_KVM-v7.4.6.M-build2588-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty500G.qcow2" "hdb_disk_image": "empty30G.qcow2"
} }
}, },
{ {
"name": "7.4.5", "name": "7.4.5",
"images": { "images": {
"hda_disk_image": "FMG_VM64_KVM-v7.4.5.M-build2553-FORTINET.out.kvm.qcow2", "hda_disk_image": "FMG_VM64_KVM-v7.4.5.M-build2553-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty500G.qcow2" "hdb_disk_image": "empty30G.qcow2"
} }
}, },
{ {
"name": "7.4.4", "name": "7.4.4",
"images": { "images": {
"hda_disk_image": "FMG_VM64_KVM-v7.4.4.F-build2550-FORTINET.out.kvm.qcow2", "hda_disk_image": "FMG_VM64_KVM-v7.4.4.F-build2550-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty500G.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"
} }
} }
] ]

View File

@ -1,6 +1,5 @@
{ {
"appliance_id": "bd86792e-9870-4b42-8f16-cb2776f1d5d5", "appliance_id": "bd86792e-9870-4b42-8f16-cb2776f1d5d5",
"tags": ["device_type:gns3_huawei_telnet_ce"],
"name": "HuaWei CE12800", "name": "HuaWei CE12800",
"category": "multilayer_switch", "category": "multilayer_switch",
"description": "CE12800 series switches are high-performance core switches designed for data center networks and high-end campus networks. The switches provide stable, reliable, secure, and high-performance Layer 2/Layer 3 switching services, to help build an elastic, virtualized, agile, and high-quality network.", "description": "CE12800 series switches are high-performance core switches designed for data center networks and high-end campus networks. The switches provide stable, reliable, secure, and high-performance Layer 2/Layer 3 switching services, to help build an elastic, virtualized, agile, and high-quality network.",

View File

@ -132,37 +132,9 @@
"md5sum": "24cd1006734993dab338e5c75f80b875", "md5sum": "24cd1006734993dab338e5c75f80b875",
"version": "26.03.0", "version": "26.03.0",
"direct_download_url": "https://github.com/kernelkit/infix/releases/download/v26.03.0/infix-x86_64-v26.03.0.qcow2" "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": [ "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", "name": "26.03.0",
"images": { "images": {

View File

@ -17,7 +17,7 @@
"qemu": { "qemu": {
"adapter_type": "virtio-net-pci", "adapter_type": "virtio-net-pci",
"adapters": 1, "adapters": 1,
"ram": 1536, "ram": 1024,
"hda_disk_interface": "virtio", "hda_disk_interface": "virtio",
"arch": "x86_64", "arch": "x86_64",
"console_type": "telnet", "console_type": "telnet",
@ -27,36 +27,60 @@
}, },
"images": [ "images": [
{ {
"filename": "OL10U1_x86_64-kvm-b270.qcow2", "filename": "OL9U5_x86_64-kvm-b259.qcow2",
"version": "10.1", "version": "9.5",
"md5sum": "c3ed48965110e0cbbd75734d3c23a2ce", "md5sum": "05e9b62c408ab49a02d6833fc683d1ad",
"filesize": 1044119552, "filesize": 652935168,
"download_url": "https://yum.oracle.com/oracle-linux-templates.html", "download_url": "https://yum.oracle.com/oracle-linux-templates.html",
"direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL10/u1/x86_64/OL10U1_x86_64-kvm-b270.qcow2" "direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL9/u5/x86_64/OL9U5_x86_64-kvm-b259.qcow2"
}, },
{ {
"filename": "OL9U7_x86_64-kvm-b269.qcow2", "filename": "OL9U2_x86_64-kvm-b197.qcow",
"version": "9.7", "version": "9.2",
"md5sum": "fe0c555620d2001bb4d4d95a53b43738", "md5sum": "2ff3d0bc8a243ad89c96215f303f1c73",
"filesize": 792985600, "filesize": 560791552,
"download_url": "https://yum.oracle.com/oracle-linux-templates.html", "download_url": "https://yum.oracle.com/oracle-linux-templates.html",
"direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL9/u7/x86_64/OL9U7_x86_64-kvm-b269.qcow2" "direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL9/u2/x86_64/OL9U2_x86_64-kvm-b197.qcow"
}, },
{ {
"filename": "OL8U10_x86_64-kvm-b271.qcow2", "filename": "OL9U1_x86_64-kvm-b158.qcow",
"version": "9.1",
"md5sum": "9f32851b96fc38191892197fa11f7435",
"filesize": 539033600,
"download_url": "https://yum.oracle.com/oracle-linux-templates.html",
"direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL9/u1/x86_64/OL9U1_x86_64-kvm-b158.qcow"
},
{
"filename": "OL8U10_x86_64-kvm-b258.qcow2",
"version": "8.10", "version": "8.10",
"md5sum": "f3184e536af1c2aba6b6f499b1a7085a", "md5sum": "bb07581af5122515b6822595ded5deef",
"filesize": 1585643520, "filesize": 1251672064,
"download_url": "https://yum.oracle.com/oracle-linux-templates.html", "download_url": "https://yum.oracle.com/oracle-linux-templates.html",
"direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL8/u10/x86_64/OL8U10_x86_64-kvm-b271.qcow2" "direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL8/u10/x86_64/OL8U10_x86_64-kvm-b258.qcow2"
}, },
{ {
"filename": "OL7U9_x86_64-kvm-b257.qcow2", "filename": "OL8U8_x86_64-kvm-b198.qcow",
"version": "7.9", "version": "8.8",
"md5sum": "d3af7cf0b8f44d298a67ce9ebe184494", "md5sum": "717622f373d77349cc102a3a325efbd3",
"filesize": 998244352, "filesize": 934215680,
"download_url": "https://yum.oracle.com/oracle-linux-templates.html", "download_url": "https://yum.oracle.com/oracle-linux-templates.html",
"direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL7/u9/x86_64/OL7U9_x86_64-kvm-b257.qcow2" "direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL8/u8/x86_64/OL8U8_x86_64-kvm-b198.qcow"
},
{
"filename": "OL8U7_x86_64-kvm-b148.qcow",
"version": "8.7",
"md5sum": "962cdde7e810888b9914e937222f687f",
"filesize": 913965056,
"download_url": "https://yum.oracle.com/oracle-linux-templates.html",
"direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL8/u7/x86_64/OL8U7_x86_64-kvm-b148.qcow"
},
{
"filename": "OL7U9_x86_64-kvm-b145.qcow",
"version": "7.9",
"md5sum": "e60d4145a69b34026db6121109ca9131",
"filesize": 725221376,
"download_url": "https://yum.oracle.com/oracle-linux-templates.html",
"direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL7/u9/x86_64/OL7U9_x86_64-kvm-b145.qcow"
}, },
{ {
"filename": "oracle-cloud-init-data.iso", "filename": "oracle-cloud-init-data.iso",
@ -69,30 +93,51 @@
], ],
"versions": [ "versions": [
{ {
"name": "10.1", "name": "9.5",
"images": { "images": {
"hda_disk_image": "OL10U1_x86_64-kvm-b270.qcow2", "hda_disk_image": "OL9U5_x86_64-kvm-b259.qcow2",
"cdrom_image": "oracle-cloud-init-data.iso" "cdrom_image": "oracle-cloud-init-data.iso"
} }
}, },
{ {
"name": "9.7", "name": "9.2",
"images": { "images": {
"hda_disk_image": "OL9U7_x86_64-kvm-b269.qcow2", "hda_disk_image": "OL9U2_x86_64-kvm-b197.qcow",
"cdrom_image": "oracle-cloud-init-data.iso"
}
},
{
"name": "9.1",
"images": {
"hda_disk_image": "OL9U1_x86_64-kvm-b158.qcow",
"cdrom_image": "oracle-cloud-init-data.iso" "cdrom_image": "oracle-cloud-init-data.iso"
} }
}, },
{ {
"name": "8.10", "name": "8.10",
"images": { "images": {
"hda_disk_image": "OL8U10_x86_64-kvm-b271.qcow2", "hda_disk_image": "OL8U10_x86_64-kvm-b258.qcow2",
"cdrom_image": "oracle-cloud-init-data.iso"
}
},
{
"name": "8.8",
"images": {
"hda_disk_image": "OL8U8_x86_64-kvm-b198.qcow",
"cdrom_image": "oracle-cloud-init-data.iso"
}
},
{
"name": "8.7",
"images": {
"hda_disk_image": "OL8U7_x86_64-kvm-b148.qcow",
"cdrom_image": "oracle-cloud-init-data.iso" "cdrom_image": "oracle-cloud-init-data.iso"
} }
}, },
{ {
"name": "7.9", "name": "7.9",
"images": { "images": {
"hda_disk_image": "OL7U9_x86_64-kvm-b257.qcow2", "hda_disk_image": "OL7U9_x86_64-kvm-b145.qcow",
"cdrom_image": "oracle-cloud-init-data.iso" "cdrom_image": "oracle-cloud-init-data.iso"
} }
} }

View File

@ -17,7 +17,7 @@
"qemu": { "qemu": {
"adapter_type": "virtio-net-pci", "adapter_type": "virtio-net-pci",
"adapters": 1, "adapters": 1,
"ram": 1536, "ram": 1024,
"hda_disk_interface": "virtio", "hda_disk_interface": "virtio",
"arch": "x86_64", "arch": "x86_64",
"console_type": "telnet", "console_type": "telnet",
@ -26,22 +26,6 @@
"options": "-nographic -cpu host" "options": "-nographic -cpu host"
}, },
"images": [ "images": [
{
"filename": "Rocky-10-GenericCloud-Base-10.1-20251116.0.x86_64.qcow2",
"version": "10.1",
"md5sum": "729d7235716bd41a0a15e07d2b44c679",
"filesize": 575406080,
"download_url": "https://download.rockylinux.org/pub/rocky/9/images/x86_64/",
"direct_download_url": "https://download.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base-10.1-20251116.0.x86_64.qcow2"
},
{
"filename": "Rocky-9-GenericCloud-Base-9.7-20251123.2.x86_64.qcow2",
"version": "9.7",
"md5sum": "4a0cbfb45b97f09b690044429aaca1c8",
"filesize": 648806400,
"download_url": "https://download.rockylinux.org/pub/rocky/9/images/x86_64/",
"direct_download_url": "https://download.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-Base-9.7-20251123.2.x86_64.qcow2"
},
{ {
"filename": "Rocky-9-GenericCloud-Base-9.5-20241118.0.x86_64.qcow2", "filename": "Rocky-9-GenericCloud-Base-9.5-20241118.0.x86_64.qcow2",
"version": "9.5", "version": "9.5",
@ -92,20 +76,6 @@
} }
], ],
"versions": [ "versions": [
{
"name": "10.1",
"images": {
"hda_disk_image": "Rocky-10-GenericCloud-Base-10.1-20251116.0.x86_64.qcow2",
"cdrom_image": "rocky-cloud-init-data.iso"
}
},
{
"name": "9.7",
"images": {
"hda_disk_image": "Rocky-9-GenericCloud-Base-9.7-20251123.2.x86_64.qcow2",
"cdrom_image": "rocky-cloud-init-data.iso"
}
},
{ {
"name": "9.5", "name": "9.5",
"images": { "images": {

View File

@ -14,7 +14,7 @@
"symbol": "linux_guest.svg", "symbol": "linux_guest.svg",
"docker": { "docker": {
"adapters": 1, "adapters": 1,
"image": "gns3/ubuntu:resolute", "image": "gns3/ubuntu:noble",
"console_type": "telnet" "console_type": "telnet"
} }
} }

View File

@ -1,86 +0,0 @@
{
"appliance_id": "90afc191-6195-4ff2-905b-5470573a882b",
"name": "Westermo WeOS",
"category": "router",
"description": "Westermo Operating System (WeOS) is a leading-edge industrial network operating system that is being continuously developed whilst being subjected to exhaustive quality testing. It powers the most reliable switches and routers on the market, designed for harsh industrial environments. WeOS has extensive support for network and security protocols that have been made simple to configure and maintain. WeOS along with Westermos robust hardware provides the worlds most reliable network solutions.",
"vendor_name": "Westermo",
"vendor_url": "https://www.westermo.com/",
"vendor_logo_url": "https://api-0831ddf0-b06c-4a4e-bcf7-afba78872de1.digizuite.app/DigizuiteCore/CollaborationService/api/share/asset/4C90E538E869D47D2782840A06F726F6D7548D864857388E38218F",
"documentation_url": "https://docs.westermo.com/weos/weos-5/",
"product_name": "WeOS",
"product_url": "https://www.westermo.com/products/software/weos",
"registry_version": 4,
"status": "stable",
"availability": "free",
"maintainer": "Westermo",
"maintainer_email": "info@westermo.com",
"usage": "\nFactory Configuration\n=====================\nAll ports are in VLAN1 untagged. The system will acquire a link-local\nIPv4 address (169.254.0.0/16) and will also request an address using\nDHCP. mDNS is enabled and the device is reachable under these names\n(where XX-XX-XX corresponds to the last three octets in the device's\nMAC address): zero-XX-XX-XX.local, zero.local, and weos.local.\n\nManagement\n==========\nAccessible via console, ssh, and http/https.\n\nUsername: admin\nPassword: admin\n\nUpgrade\n=======\nTo upgrade a device, simply download the new version and replace the\nHDA (Primary Master) image under the HDD tab in the configuration pane\nof the device.\n",
"symbol": ":/symbols/classic/router.svg",
"port_name_format": "eth{0}",
"linked_clone": true,
"qemu": {
"adapter_type": "virtio-net-pci",
"adapters": 8,
"ram": 512,
"cpus": 1,
"hda_disk_interface": "virtio",
"hdb_disk_interface": "virtio",
"arch": "x86_64",
"console_type": "telnet",
"kvm": "allow",
"options": "-nographic --machine pc-i440fx-4.2"
},
"images": [
{
"filename": "Config-zero-1.0.0.disk",
"version": "1.0.0",
"md5sum": "afe7b74683971fec48802997f6470ca5",
"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",
"md5sum": "7b4e29761091c12ec2cd482f7c1a0bea",
"filesize": 75497472,
"direct_download_url": "https://dropzone.westermo.com/file.aspx?id=4926adbe-0cd6-4851-b70f-e9d60b3b3f06"
},
{
"filename": "WeOS-zero-5.27.0.disk",
"version": "5.27.0",
"md5sum": "8bd4944b60eaeca391bb5d1dc0defb8b",
"filesize": 78643200,
"direct_download_url": "https://dropzone.westermo.com/file.aspx?id=1a7bf389-a4b1-4dae-b121-6fb3d6781542"
}
],
"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": {
"hda_disk_image": "WeOS-zero-5.28.0.disk",
"hdb_disk_image": "Config-zero-1.0.0.disk"
}
},
{
"name": "5.27.0",
"images": {
"hda_disk_image": "WeOS-zero-5.27.0.disk",
"hdb_disk_image": "Config-zero-1.0.0.disk"
}
}
]
}

View File

@ -311,7 +311,7 @@ class Cloud(BaseNode):
if not port_info["interface"] in network_interfaces: if not port_info["interface"] in network_interfaces:
raise NodeError("Interface '{}' could not be found on this system, please update '{}'".format(port_info["interface"], self.name)) raise NodeError("Interface '{}' could not be found on this system, please update '{}'".format(port_info["interface"], self.name))
if sys.platform.startswith("linux") or sys.platform.startswith("openbsd"): if sys.platform.startswith("linux"):
await self._add_linux_ethernet(port_info, bridge_name) await self._add_linux_ethernet(port_info, bridge_name)
elif sys.platform.startswith("darwin"): elif sys.platform.startswith("darwin"):
await self._add_osx_ethernet(port_info, bridge_name) await self._add_osx_ethernet(port_info, bridge_name)

View File

@ -33,7 +33,7 @@ from gns3server.config import Config
from gns3server.utils.asyncio import locking from gns3server.utils.asyncio import locking
from gns3server.compute.base_manager import BaseManager from gns3server.compute.base_manager import BaseManager
from gns3server.compute.docker.docker_vm import DockerVM from gns3server.compute.docker.docker_vm import DockerVM
from gns3server.compute.docker.docker_error import DockerError, DockerHttp304Error, DockerHttp404Error, DockerHttp409Error from gns3server.compute.docker.docker_error import DockerError, DockerHttp304Error, DockerHttp404Error
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -236,8 +236,6 @@ class Docker(BaseManager):
raise DockerHttp304Error("Docker has returned an error: {} {}".format(response.status, body)) raise DockerHttp304Error("Docker has returned an error: {} {}".format(response.status, body))
elif response.status == 404: elif response.status == 404:
raise DockerHttp404Error("Docker has returned an error: {} {}".format(response.status, body)) 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: else:
raise DockerError("Docker has returned an error: {} {}".format(response.status, body)) raise DockerError("Docker has returned an error: {} {}".format(response.status, body))
return response return response

View File

@ -32,7 +32,3 @@ class DockerHttp304Error(DockerError):
class DockerHttp404Error(DockerError): class DockerHttp404Error(DockerError):
pass pass
class DockerHttp409Error(DockerError):
pass

View File

@ -43,8 +43,7 @@ from ..nios.nio_udp import NIOUDP
from .docker_error import ( from .docker_error import (
DockerError, DockerError,
DockerHttp304Error, DockerHttp304Error,
DockerHttp404Error, DockerHttp404Error
DockerHttp409Error
) )
import logging import logging
@ -460,31 +459,10 @@ class DockerVM(BaseNode):
if extra_hosts: if extra_hosts:
params["Env"].append("GNS3_EXTRA_HOSTS={}".format(extra_hosts)) params["Env"].append("GNS3_EXTRA_HOSTS={}".format(extra_hosts))
try: # Support name in Doker: [a-zA-Z0-9][a-zA-Z0-9_.-]
# Supported names in Docker: [a-zA-Z0-9][a-zA-Z0-9_.-] result = await self.manager.query("POST", "containers/create?name={}".format(self.docker_name), data=params)
result = await self.manager.query("POST", f"containers/create?name={self.docker_name}", data=params) self._cid = result['Id']
except DockerHttp409Error: log.info("Docker container '{name}' [{id}] created".format(name=self._name, id=self._id))
# 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 return True
def _format_env(self, variables, env): def _format_env(self, variables, env):
@ -869,7 +847,7 @@ class DockerVM(BaseNode):
await self._fix_permissions() await self._fix_permissions()
state = await self._get_container_state() state = await self._get_container_state()
if state != "stopped" and state != "exited": if state != "stopped" or state != "exited":
# t=5 number of seconds to wait before killing the container # t=5 number of seconds to wait before killing the container
try: try:
await self.manager.query("POST", "containers/{}/stop".format(self._cid), params={"t": 5}) await self.manager.query("POST", "containers/{}/stop".format(self._cid), params={"t": 5})

View File

@ -578,7 +578,7 @@ class IOUVM(BaseNode):
callback = functools.partial(self._termination_callback, "IOU") callback = functools.partial(self._termination_callback, "IOU")
gns3server.utils.asyncio.monitor_process(self._iou_process, callback) gns3server.utils.asyncio.monitor_process(self._iou_process, callback)
except FileNotFoundError as e: except FileNotFoundError as e:
raise IOUError("Could not start IOU: {}: 32-bit binary support is probably not installed, it is recommended to use a 64-bit image instead".format(e)) raise IOUError("Could not start IOU: {}: 32-bit binary support is probably not installed".format(e))
except (OSError, subprocess.SubprocessError) as e: except (OSError, subprocess.SubprocessError) as e:
iou_stdout = self.read_iou_stdout() iou_stdout = self.read_iou_stdout()
log.error("Could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout)) log.error("Could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout))

View File

@ -35,7 +35,6 @@ import time
import json import json
import psutil import psutil
from pathlib import Path
from gns3server.utils import parse_version, shlex_quote from gns3server.utils import parse_version, shlex_quote
from gns3server.utils.asyncio import subprocess_check_output, cancellable_wait_run_in_executor from gns3server.utils.asyncio import subprocess_check_output, cancellable_wait_run_in_executor
from .qemu_error import QemuError from .qemu_error import QemuError
@ -2058,23 +2057,15 @@ class QemuVM(BaseNode):
options.extend(["-bios", self._bios_image.replace(",", ",,")]) options.extend(["-bios", self._bios_image.replace(",", ",,")])
elif self._uefi: 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") old_ovmf_vars_path = os.path.join(self.working_dir, "OVMF_VARS.fd")
if os.path.exists(old_ovmf_vars_path): 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 # 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") ovmf_firmware_path = self.manager.get_abs_image_path("OVMF_CODE.fd")
else: else:
# Use a manual case-insensitive search instead system_ovmf_firmware_path = "/usr/share/OVMF/OVMF_CODE_4M.fd"
try: if os.path.exists(system_ovmf_firmware_path):
system_ovmf_firmware_path = next((f for f in system_ovmf_firmware_dir.glob("*.fd") ovmf_firmware_path = system_ovmf_firmware_path
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: else:
# otherwise, get the UEFI firmware from the images directory # otherwise, get the UEFI firmware from the images directory
ovmf_firmware_path = self.manager.get_abs_image_path("OVMF_CODE_4M.fd") ovmf_firmware_path = self.manager.get_abs_image_path("OVMF_CODE_4M.fd")
@ -2083,13 +2074,9 @@ class QemuVM(BaseNode):
options.extend(["-drive", "if=pflash,format=raw,readonly,file={}".format(ovmf_firmware_path)]) options.extend(["-drive", "if=pflash,format=raw,readonly,file={}".format(ovmf_firmware_path)])
# try to use the UEFI variables store from the system first # try to use the UEFI variables store from the system first
try: system_ovmf_vars_path = "/usr/share/OVMF/OVMF_VARS_4M.fd"
system_ovmf_vars_path = next((f for f in system_ovmf_firmware_dir.glob("*.fd") if os.path.exists(system_ovmf_vars_path):
if f.name.lower() == "ovmf_vars_4m.fd"), None) ovmf_vars_path = system_ovmf_vars_path
except (FileNotFoundError, StopIteration):
system_ovmf_vars_path = None
if system_ovmf_vars_path:
ovmf_vars_path = str(system_ovmf_vars_path)
else: else:
# otherwise, get the UEFI variables store from the images directory # otherwise, get the UEFI variables store from the images directory
ovmf_vars_path = self.manager.get_abs_image_path("OVMF_VARS_4M.fd") ovmf_vars_path = self.manager.get_abs_image_path("OVMF_VARS_4M.fd")
@ -2105,10 +2092,6 @@ class QemuVM(BaseNode):
except OSError as e: except OSError as e:
raise QemuError("Cannot copy OVMF_VARS_4M.fd file to the node working directory: {}".format(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)]) 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 return options
def _linux_boot_options(self): def _linux_boot_options(self):
@ -2480,6 +2463,7 @@ class QemuVM(BaseNode):
elif sys.platform.startswith("win") or sys.platform.startswith("darwin"): elif sys.platform.startswith("win") or sys.platform.startswith("darwin"):
command.extend(["-enable-hax"]) command.extend(["-enable-hax"])
command.extend(["-boot", "order={}".format(self._boot_priority)]) command.extend(["-boot", "order={}".format(self._boot_priority)])
command.extend(self._bios_option())
command.extend(self._cdrom_option()) command.extend(self._cdrom_option())
command.extend((await self._disk_options())) command.extend((await self._disk_options()))
command.extend(self._linux_boot_options()) command.extend(self._linux_boot_options())
@ -2497,8 +2481,6 @@ class QemuVM(BaseNode):
raise QemuError("Console type {} is unknown".format(self._console_type)) raise QemuError("Console type {} is unknown".format(self._console_type))
command.extend(self._monitor_options()) command.extend(self._monitor_options())
command.extend((await self._network_options())) command.extend((await self._network_options()))
# bios options must be last to have predictable NIC numbering, see https://github.com/GNS3/gns3-server/issues/2838
command.extend(self._bios_option())
if self.on_close != "save_vm_state": if self.on_close != "save_vm_state":
await self._clear_save_vm_stated() await self._clear_save_vm_stated()
else: else:

View File

@ -562,15 +562,7 @@ class Controller:
for project in self._projects.values(): for project in self._projects.values():
if project.auto_open: if project.auto_open:
try: await project.open()
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): def get_free_project_name(self, base_name):
""" """

View File

@ -166,52 +166,24 @@ async def import_project(
project = await controller.load_project(dot_gns3_path, load=False) project = await controller.load_project(dot_gns3_path, load=False)
return project return project
def _create_symbolic_links(zip_file, path): def _create_symbolic_links(zip_file, path):
""" """
Manually create symbolic links (if any) because ZipFile does not support it. Manually create symbolic links (if any) because ZipFile does not support it.
Refuse any target that escapes `path`.
:param zip_file: ZipFile instance :param zip_file: ZipFile instance
:param path: project location :param path: project location
""" """
path_root = os.path.realpath(path) + os.sep
for zip_info in zip_file.infolist(): for zip_info in zip_file.infolist():
if not stat.S_ISLNK(zip_info.external_attr >> 16): if stat.S_ISLNK(zip_info.external_attr >> 16):
continue symlink_target = zip_file.read(zip_info.filename).decode()
symlink_target = zip_file.read(zip_info.filename).decode() symlink_path = os.path.join(path, zip_info.filename)
symlink_path = os.path.join(path, zip_info.filename) try:
# remove the regular file and replace it by a symbolic link
# 1. Reject absolute targets outright. os.remove(symlink_path)
if os.path.isabs(symlink_target): os.symlink(symlink_target, symlink_path)
raise aiohttp.web.HTTPConflict( except OSError as e:
text=f"Symlink {zip_info.filename!r} has absolute target {symlink_target!r}, refusing" raise aiohttp.web.HTTPConflict(text=f"Cannot create symbolic link: {e}")
)
# 2. Reject paths where the entry name itself escapes (defence in depth;
# extractall normally would already have caught this).
member_abs = os.path.realpath(symlink_path)
if not (member_abs + os.sep).startswith(path_root) and member_abs + os.sep != path_root:
raise aiohttp.web.HTTPConflict(
text=f"Symlink entry {zip_info.filename!r} escapes project dir, refusing"
)
# 3. Resolve the symlink target relative to the entry's own parent
# directory and verify the resolved real path stays inside `path`.
link_dir = os.path.realpath(os.path.dirname(symlink_path))
resolved_target = os.path.realpath(os.path.join(link_dir, symlink_target))
if not (resolved_target + os.sep).startswith(path_root) and resolved_target + os.sep != path_root:
raise aiohttp.web.HTTPConflict(
text=f"Symlink {zip_info.filename!r} -> {symlink_target!r} escapes project dir, refusing"
)
try:
os.remove(symlink_path)
os.symlink(symlink_target, symlink_path)
except OSError as e:
raise aiohttp.web.HTTPConflict(text=f"Cannot create symbolic link: {e}")
def regenerate_topology_ids(topology, new_project_path, reset_mac_addresses=False): def regenerate_topology_ids(topology, new_project_path, reset_mac_addresses=False):
""" """
@ -299,7 +271,7 @@ async def _upload_file(compute, project_id, file_path, path):
async def _import_images(controller, images_path): async def _import_images(controller, images_path):
""" """
Copy images to the images directory or delete them if they already exist. Copy images to the images directory or delete them if they already exists.
""" """
image_dir = controller.images_path() image_dir = controller.images_path()
@ -307,19 +279,12 @@ async def _import_images(controller, images_path):
for (dirpath, dirnames, filenames) in os.walk(root, followlinks=False): for (dirpath, dirnames, filenames) in os.walk(root, followlinks=False):
for filename in filenames: for filename in filenames:
path = os.path.join(dirpath, filename) path = os.path.join(dirpath, filename)
if os.path.islink(path):
continue
dst = os.path.join(image_dir, os.path.relpath(path, root)) dst = os.path.join(image_dir, os.path.relpath(path, root))
os.makedirs(os.path.dirname(dst), exist_ok=True) os.makedirs(os.path.dirname(dst), exist_ok=True)
if not os.path.exists(dst): await wait_run_in_executor(shutil.move, path, 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): async def update_snapshots(snapshots_dir, project_path, project_name, project_id, reset_mac_addresses=True):
""" """
@ -351,7 +316,7 @@ async def update_snapshots(snapshots_dir, project_path, project_name, project_id
topology = json.load(f) topology = json.load(f)
topology["name"] = project_name topology["name"] = project_name
topology["project_id"] = project_id topology["project_id"] = project_id
regenerate_topology_ids(topology, tmpdir, reset_mac_addresses) regenerate_topology_ids(topology, project_path, reset_mac_addresses)
with open(topology_file_path, "w+", encoding="utf-8") as f: with open(topology_file_path, "w+", encoding="utf-8") as f:
json.dump(topology, f, indent=4, sort_keys=True) json.dump(topology, f, indent=4, sort_keys=True)
except OSError as e: except OSError as e:

View File

@ -779,9 +779,8 @@ class Project:
try: try:
with open(self._snapshot_conf_path, encoding="utf-8") as f: with open(self._snapshot_conf_path, encoding="utf-8") as f:
self._snapshot_conf = json.load(f) self._snapshot_conf = json.load(f)
except (OSError, UnicodeDecodeError, ValueError): except (OSError, UnicodeDecodeError, ValueError) as e:
log.exception("Could not read snapshot config %s", self._snapshot_conf_path) raise aiohttp.web.HTTPConflict(text="Could not read snapshot config {}: {}".format(self._snapshot_conf_path, str(e)))
raise aiohttp.web.HTTPConflict(text="Could not read snapshot configuration file")
# Load all legacy snapshots (.gns3project files) to create an initial snapshot config if it doesn't exist # Load all legacy snapshots (.gns3project files) to create an initial snapshot config if it doesn't exist
if os.path.exists(snapshot_dir) and not self._snapshot_conf: if os.path.exists(snapshot_dir) and not self._snapshot_conf:
@ -905,23 +904,12 @@ class Project:
async def delete(self): 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": if self._status != "opened":
try: try:
await self.open(auto_start=False) await self.open()
except aiohttp.web.HTTPConflict as e: except aiohttp.web.HTTPConflict as e:
# ignore missing images or other conflicts when deleting a project # ignore missing images or other conflicts when deleting a project
log.warning(f"Conflict while deleting project: {e}") log.warning("Conflict while deleting project: {}".format(e.text))
await self.delete_on_computes() await self.delete_on_computes()
await self.close() await self.close()
try: try:
@ -933,42 +921,6 @@ class Project:
raise aiohttp.web.HTTPConflict(text="Cannot delete project directory {}: {}".format(self.path, str(e))) raise aiohttp.web.HTTPConflict(text="Cannot delete project directory {}: {}".format(self.path, str(e)))
self.emit_controller_notification("project.deleted", self.__json__()) 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): async def delete_on_computes(self):
""" """
Delete the project on computes but not on controller Delete the project on computes but not on controller
@ -998,12 +950,9 @@ class Project:
return os.path.join(self.path, self._filename) return os.path.join(self.path, self._filename)
@locking @locking
async def open(self, auto_start=True): async def open(self):
""" """
Load topology elements Load topology elements
:param auto_start: whether the nodes may be started when the project
has auto start enabled
""" """
if self._closing: if self._closing:
@ -1117,7 +1066,7 @@ class Project:
self._loading = False self._loading = False
self.emit_controller_notification("project.opened", self.__json__()) self.emit_controller_notification("project.opened", self.__json__())
# Should we start the nodes when project is open # Should we start the nodes when project is open
if self._auto_start and auto_start: if self._auto_start:
# Start all in the background without waiting for completion # Start all in the background without waiting for completion
# we ignore errors because we want to let the user open # we ignore errors because we want to let the user open
# their project and fix it # their project and fix it

View File

@ -139,7 +139,7 @@ class Snapshot:
# delete the current project files # delete the current project files
project_files_path = os.path.join(self._project.path, "project-files") project_files_path = os.path.join(self._project.path, "project-files")
if os.path.exists(project_files_path): if os.path.exists(project_files_path):
await wait_run_in_executor(shutil.rmtree, project_files_path, ignore_errors=True) await wait_run_in_executor(shutil.rmtree, project_files_path)
with open(self._path, "rb") as f: with open(self._path, "rb") as f:
project = await import_project( project = await import_project(
self._project.controller, self._project.controller,

View File

@ -57,7 +57,7 @@ class CrashReport:
Report crash to a third party service Report crash to a third party service
""" """
DSN = "https://89ba0bf8d773c2c95518bfb696d6d86f@o19455.ingest.us.sentry.io/38482" DSN = "https://74851857a3f05aecd909415e2a4cbd60@o19455.ingest.us.sentry.io/38482"
_instance = None _instance = None
def __init__(self): def __init__(self):

View File

@ -22,7 +22,6 @@ from gns3server.schemas.template import TEMPLATE_USAGE_SCHEMA
import hashlib import hashlib
import json import json
import os
from gns3server.schemas.template import ( from gns3server.schemas.template import (
TEMPLATE_OBJECT_SCHEMA, TEMPLATE_OBJECT_SCHEMA,
@ -174,131 +173,3 @@ class TemplateHandler:
compute_id=request.json.get("compute_id")) compute_id=request.json.get("compute_id"))
response.set_status(201) response.set_status(201)
response.json(node) response.json(node)
@Route.get(
r"/templates/{template_id}/base-config/{filename}",
description="Get base configuration file content",
)
def get_base_config(request, response):
controller = Controller.instance()
template_id = request.match_info["template_id"]
template = controller.template_manager.get_template(template_id)
filename = os.path.basename(request.match_info["filename"])
path = os.path.join(controller.configs_path(), filename)
try:
if not os.path.exists(path):
response.set_status(404)
response.json({"message": "File not found"})
return
with open(path, encoding="utf-8", errors="ignore") as f:
content = f.read()
except Exception as e:
response.set_status(500)
response.json({"message": str(e)})
return
response.set_status(200)
response.json({
"template_id": template.id,
"filename": filename,
"content": content
})
@Route.put(
r"/templates/{template_id}/base-config/{filename}",
description="Update base configuration file content",
parameters={
"template_id": "Template UUID",
"filename": "Base config filename"
},
status_codes={
200: "File updated",
400: "Invalid request",
404: "Template or file not found"
},
)
def update_base_config(request, response):
controller = Controller.instance()
template_id = request.match_info["template_id"]
filename = os.path.basename(request.match_info["filename"])
try:
template = controller.template_manager.get_template(template_id)
except Exception:
response.set_status(404)
response.json({"message": "Template not found"})
return
path = os.path.join(controller.configs_path(), filename)
body = request.json
if not body or "content" not in body:
response.set_status(400)
response.json({"message": "Missing 'content' field"})
return
content = body["content"]
try:
os.makedirs(controller.configs_path(), exist_ok=True)
with open(path, "w", encoding="utf-8") as f:
f.write(content)
except OSError as e:
response.set_status(500)
response.json({"message": str(e)})
return
response.set_status(200)
response.json({
"template_id": template.id,
"filename": filename,
"content": content
})
@Route.get(
r"/templates/base-configs",
description="List all available base configuration files",
status_codes={
200: "List of base configuration files returned"
}
)
def list_base_configs(request, response):
controller = Controller.instance()
configs_path = controller.configs_path()
try:
files = []
if os.path.exists(configs_path):
for filename in os.listdir(configs_path):
path = os.path.join(configs_path, filename)
if os.path.isfile(path):
files.append({"filename": filename})
except OSError as e:
response.set_status(500)
response.json({
"message": str(e)
})
return
files = sorted(files, key=lambda x: x["filename"])
response.set_status(200)
response.json(files)

View File

@ -215,32 +215,18 @@ class AsyncioTelnetServer:
await self._write_intro(network_writer, echo=self._echo, binary=self._binary, naws=self._naws) await self._write_intro(network_writer, echo=self._echo, binary=self._binary, naws=self._naws)
await connection.connected() await connection.connected()
await self._process(network_reader, network_writer, connection) await self._process(network_reader, network_writer, connection)
except (ConnectionError, OSError, asyncio.CancelledError): except (ConnectionError, OSError):
pass
except Exception:
# Catch any unexpected exception so the cleanup below still runs.
# Without the try/finally, an uncaught exception here would leave
# _reader_process pinned to a dead reader, and subsequent client
# connections would see _get_reader() return None and never
# receive node output -- the "silent proxy" hang (issue #2344).
log.exception("Unexpected error in telnet proxy; cleaning up client connection...")
finally:
async with self._lock: async with self._lock:
try: network_writer.close()
network_writer.close() # await network_writer.wait_closed() # this doesn't work in Python 3.6
finally: if self._reader_process == network_reader:
if self._reader_process == network_reader: self._reader_process = None
self._reader_process = None # Cancel current read from this reader
# Cancel current read from this reader if self._current_read is not None:
if self._current_read is not None: self._current_read.cancel()
self._current_read.cancel()
self._current_read = None await connection.disconnected()
try: del self._connections[network_writer]
await connection.disconnected()
finally:
# Use pop() to avoid KeyError if connection was already removed
# elsewhere (e.g. by the broadcast loop's timeout handler)
self._connections.pop(network_writer, None)
async def close(self): async def close(self):
for writer, connection in self._connections.items(): for writer, connection in self._connections.items():
@ -332,7 +318,7 @@ class AsyncioTelnetServer:
except (OSError, ConnectionError, asyncio.TimeoutError) as e: except (OSError, ConnectionError, asyncio.TimeoutError) as e:
log.debug(f"Error sending data to client {client_info}: {e}, closing and removing from connection table.") log.debug(f"Error sending data to client {client_info}: {e}, closing and removing from connection table.")
connection.close() connection.close()
self._connections.pop(connection_key, None) del self._connections[connection_key]
async def _read(self, cmd, buffer, location, reader): async def _read(self, cmd, buffer, location, reader):
""" Reads next op from the buffer or reader""" """ Reads next op from the buffer or reader"""

View File

@ -147,7 +147,7 @@ def is_interface_up(interface):
:returns: boolean :returns: boolean
""" """
if sys.platform.startswith("linux") or sys.platform.startswith("openbsd"): if sys.platform.startswith("linux"):
if interface not in psutil.net_if_addrs(): if interface not in psutil.net_if_addrs():
return False return False
@ -234,7 +234,7 @@ def interfaces():
result["special"] = False result["special"] = False
for special_interface in ("lo", "vmnet", "vboxnet", "docker", "lxcbr", for special_interface in ("lo", "vmnet", "vboxnet", "docker", "lxcbr",
"virbr", "ovs-system", "veth", "fw", "p2p", "virbr", "ovs-system", "veth", "fw", "p2p",
"bridge", "vmware", "virtualbox", "gns3","veb"): "bridge", "vmware", "virtualbox", "gns3"):
if result["name"].lower().startswith(special_interface): if result["name"].lower().startswith(special_interface):
result["special"] = True result["special"] = True
for special_interface in ("-nic"): for special_interface in ("-nic"):

View File

@ -23,8 +23,8 @@
# or negative for a release candidate or beta (after the base version # or negative for a release candidate or beta (after the base version
# number has been incremented) # number has been incremented)
__version__ = "2.2.61" __version__ = "2.2.58"
__version_info__ = (2, 2, 61, 0) __version_info__ = (2, 2, 58, 0)
if "dev" in __version__: if "dev" in __version__:
try: try:

View File

@ -1,11 +1,10 @@
jsonschema==4.25.1; python_version == '3.9' # version 4.25.1 is the last to support Python 3.9 jsonschema>=4.25.1,<4.26 # version 4.25.1 is the last to support Python 3.9
jsonschema>=4.26.0,<4.27; python_version >= '3.10' aiohttp>=3.13.3,<3.14
aiohttp>=3.13.5,<3.14
aiohttp-cors>=0.8.1,<0.9 aiohttp-cors>=0.8.1,<0.9
aiofiles>=25.1.0,<26.0 aiofiles>=25.1.0,<26.0
Jinja2>=3.1.6,<3.2 Jinja2>=3.1.6,<3.2
sentry-sdk>=2.59.0,<3 # optional dependency sentry-sdk>=2.50.0,<3 # optional dependency
psutil>=7.2.2 psutil>=7.2.1
async-timeout>=5.0.1,<5.1 # this library has effectively been upstreamed into Python 3.11+ async-timeout>=5.0.1,<5.1 # this library has effectively been upstreamed into Python 3.11+
distro>=1.9.0 distro>=1.9.0
py-cpuinfo>=9.0.0,<10.0 py-cpuinfo>=9.0.0,<10.0

View File

@ -64,7 +64,7 @@ setup(
include_package_data=True, include_package_data=True,
zip_safe=False, zip_safe=False,
platforms="any", platforms="any",
python_requires=">=3.9", python_requires=">=3.8",
setup_requires=["setuptools>=45.2"], setup_requires=["setuptools>=45.2"],
classifiers=[ classifiers=[
"Development Status :: 5 - Production/Stable", "Development Status :: 5 - Production/Stable",

View File

@ -1503,19 +1503,3 @@ async def test_read_console_output_with_binary_mode(vm):
with asyncio_patch('gns3server.compute.docker.docker_vm.DockerVM.stop'): with asyncio_patch('gns3server.compute.docker.docker_vm.DockerVM.stop'):
await vm._read_console_output(input_stream, output_stream) await vm._read_console_output(input_stream, output_stream)
output_stream.feed_data.assert_called_once_with(b"test") output_stream.feed_data.assert_called_once_with(b"test")
async def test_stop_exited_container_no_stop_query(vm):
vm._ubridge_hypervisor = None
vm._fix_permissions = MagicMock()
with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="exited"):
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query:
vm._permissions_fixed = False
await vm.stop()
assert not any(
call.args[:2] == ("POST", "containers/e90e34656842/stop")
for call in mock_query.mock_calls
)
assert vm.status == "stopped"

View File

@ -19,8 +19,6 @@ import os
import uuid import uuid
import json import json
import zipfile import zipfile
import pytest
import aiohttp
from tests.utils import asyncio_patch, AsyncioMagicMock from tests.utils import asyncio_patch, AsyncioMagicMock
from unittest.mock import patch, MagicMock from unittest.mock import patch, MagicMock
@ -119,48 +117,36 @@ async def write_file(path, z):
f.write(chunk) f.write(chunk)
@pytest.fixture async def test_import_project_containing_symlink(tmpdir, controller):
def export_project_with_symlink(tmpdir, controller):
async def _export(symlink_target):
project = Project(controller=controller, name="test")
project.dump = MagicMock()
topology = { project = Project(controller=controller, name="test")
"project_id": str(uuid.uuid4()), project.dump = MagicMock()
"name": "test", path = project.path
"auto_open": True,
"auto_start": True,
"topology": {
},
"version": "2.0.0"
}
with open(os.path.join(project.path, "project.gns3"), 'w+') as f:
json.dump(topology, f)
os.makedirs(os.path.join(project.path, "vm1", "dynamips"))
symlink_path = os.path.join(project.path, "vm1", "dynamips", "symlink")
os.symlink(symlink_target, symlink_path)
zip_path = str(tmpdir / "project.zip")
with aiozipstream.ZipFile() as z:
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir / "IOS"),):
await export_project(z, project, str(tmpdir), include_images=False)
await write_file(zip_path, z)
return zip_path
return _export
async def test_import_project_containing_symlink(controller, export_project_with_symlink):
"""
Test importing a project containing a valid symlink (target inside the project directory).
"""
project_id = str(uuid.uuid4()) project_id = str(uuid.uuid4())
symlink_target = "../symlink_target" topology = {
zip_path = await export_project_with_symlink(symlink_target) "project_id": str(uuid.uuid4()),
"name": "test",
"auto_open": True,
"auto_start": True,
"topology": {
},
"version": "2.0.0"
}
with open(os.path.join(path, "project.gns3"), 'w+') as f:
json.dump(topology, f)
os.makedirs(os.path.join(path, "vm1", "dynamips"))
symlink_path = os.path.join(project.path, "vm1", "dynamips", "symlink")
symlink_target = "/tmp/anywhere"
os.symlink(symlink_target, symlink_path)
zip_path = str(tmpdir / "project.zip")
with aiozipstream.ZipFile() as z:
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir / "IOS"),):
await export_project(z, project, str(tmpdir), include_images=False)
await write_file(zip_path, z)
with open(zip_path, "rb") as f: with open(zip_path, "rb") as f:
project = await import_project(controller, project_id, f) project = await import_project(controller, project_id, f)
@ -172,36 +158,6 @@ async def test_import_project_containing_symlink(controller, export_project_with
assert os.readlink(symlink_path) == symlink_target assert os.readlink(symlink_path) == symlink_target
async def test_import_project_containing_absolute_symlink(controller, export_project_with_symlink):
"""
Test importing a project containing an absolute symlink.
This should fail because absolute symlinks are not allowed for security reasons.
"""
project_id = str(uuid.uuid4())
symlink_target = "/tmp/anywhere"
zip_path = await export_project_with_symlink(symlink_target)
with pytest.raises(aiohttp.web.HTTPConflict):
with open(zip_path, "rb") as f:
await import_project(controller, project_id, f)
async def test_import_project_containing_escaping_symlink(controller, export_project_with_symlink):
"""
Test importing a project containing a symlink that escapes the project directory.
This should fail because symlinks that escape the project directory are not allowed for security reasons.
"""
project_id = str(uuid.uuid4())
symlink_target = "../../../../symlink_target"
zip_path = await export_project_with_symlink(symlink_target)
with pytest.raises(aiohttp.web.HTTPConflict):
with open(zip_path, "rb") as f:
await import_project(controller, project_id, f)
async def test_import_upgrade(tmpdir, controller): async def test_import_upgrade(tmpdir, controller):
""" """
Topology made for previous GNS3 version are upgraded during the process Topology made for previous GNS3 version are upgraded during the process

View File

@ -655,19 +655,6 @@ async def test_delete(project):
assert not os.path.exists(project.path) assert not os.path.exists(project.path)
async def test_delete_does_not_start_nodes(project):
"""
Deleting a project must not start its nodes, even when auto_start is enabled.
"""
project.auto_start = True
project.dump()
await project.close()
project.start_all = AsyncioMagicMock()
await project.delete()
assert not project.start_all.called
async def test_dump(projects_dir): async def test_dump(projects_dir):
directory = projects_dir directory = projects_dir

View File

@ -14,7 +14,8 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import uuid import uuid
from tests.utils import asyncio_patch from tests.utils import asyncio_patch
@ -954,81 +955,3 @@ async def test_create_node_from_template(controller_api, controller, project):
mock.assert_called_with(id, x=42, y=12, name=None, compute_id=None) mock.assert_called_with(id, x=42, y=12, name=None, compute_id=None)
assert response.route == "/projects/{project_id}/templates/{template_id}" assert response.route == "/projects/{project_id}/templates/{template_id}"
assert response.status == 201 assert response.status == 201
async def test_get_base_config(controller_api, controller):
template_id = str(uuid.uuid4())
controller.template_manager._templates[template_id] = Template(template_id, {
"template_type": "vpcs",
"category": 0,
"name": "test",
"symbol": "guest.svg",
"default_name_format": "{name}-{0}",
"compute_id": "local"
})
config_path = os.path.join(controller.configs_path(), "test_config.txt")
with open(config_path, "w") as f:
f.write("hello config")
response = await controller_api.get(
f"/templates/{template_id}/base-config/test_config.txt"
)
assert response.status == 200
assert response.json["filename"] == "test_config.txt"
assert response.json["content"] == "hello config"
async def test_update_base_config(controller_api, controller):
template_id = str(uuid.uuid4())
controller.template_manager._templates[template_id] = Template(template_id, {
"template_type": "vpcs",
"category": 0,
"name": "test",
"symbol": "guest.svg",
"default_name_format": "{name}-{0}",
"compute_id": "local"
})
config_path = os.path.join(controller.configs_path(), "update_test.txt")
with open(config_path, "w") as f:
f.write("old content")
response = await controller_api.put(
f"/templates/{template_id}/base-config/update_test.txt",
{
"content": "new updated content"
}
)
assert response.status == 200
assert response.json["content"] == "new updated content"
with open(config_path) as f:
assert f.read() == "new updated content"
async def test_list_base_configs(controller_api, controller):
config1 = os.path.join(controller.configs_path(), "config1.txt")
config2 = os.path.join(controller.configs_path(), "config2.txt")
with open(config1, "w") as f:
f.write("test1")
with open(config2, "w") as f:
f.write("test2")
response = await controller_api.get("/templates/base-configs")
assert response.status == 200
filenames = [item["filename"] for item in response.json]
assert "config1.txt" in filenames
assert "config2.txt" in filenames