1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-12-30 18:50:58 +00:00

Merge remote-tracking branch 'origin/3.0' into gh-pages

This commit is contained in:
github-actions 2024-08-11 17:36:16 +00:00
commit bb8cf65a13
61 changed files with 1330 additions and 142 deletions

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@v0.4.0 - 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

@ -13,58 +13,81 @@ name: "CodeQL"
on: on:
push: push:
branches: [ master ] branches: [ "master" ]
pull_request: pull_request:
# The branches below must be a subset of the branches above branches: [ "master" ]
branches: [ master ]
schedule: schedule:
- cron: '44 1 * * 3' - cron: '21 12 * * 4'
jobs: jobs:
analyze: analyze:
name: Analyze name: Analyze (${{ matrix.language }})
runs-on: ubuntu-latest # Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions: permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read actions: read
contents: read contents: read
security-events: write
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
language: [ 'python' ] include:
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - language: python
# Learn more about CodeQL language support at https://git.io/codeql-language-support build-mode: none
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# 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@v2 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@v1 uses: github/codeql-action/init@v3
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file. # By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file. # Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# If this step fails, then you should remove it and run the build manually (see below) # queries: security-extended,security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines shell: bash
# and modify them (or add more) to build your code if your project run: |
# uses a compiled language echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
#- run: | 'your code, for example:'
# make bootstrap echo ' make bootstrap'
# make release echo ' make release'
exit 1
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1 uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

View File

@ -12,11 +12,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
ref: "gh-pages" ref: "gh-pages"
- uses: actions/setup-python@v3 - 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

@ -20,9 +20,9 @@ jobs:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3 uses: actions/setup-python@v5
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
- name: Display Python version - name: Display Python version

View File

@ -1,5 +1,32 @@
# Change Log # Change Log
## 3.0.0rc1 11/08/2024
* Bundle web-ui v3.0.0rc1
* Convert topologies < 3.0 to have valid node hostnames
* Fix to access resources_path and install_builtin_appliances settings
## 2.2.49 06/08/2024
* Bundle web-ui v2.2.49
* Forbid -nic and -nicdev in Qemu additional options. Fixes https://github.com/GNS3/gns3-server/issues/2397
* Upgrade jsonschema and sentry-sdk packages
* Update IOU base configs to use "no ip domain lookup". Fixes #2404
## 2.2.48.1 12/07/2024
* Bundle web-ui v2.2.48.1
## 2.2.48 08/07/2024
* Bundle web-ui v2.2.48
* Add 'install_builtin_appliances' and 'resources_path' settings in the server config
* Option to keep the compute IDs unchanged when exporting a project
* Forbid unsafe Qemu additional options
* Fix error when snapshot exists with an underscore in the name
* Upgrade sentry-sdk, psutil and aiofiles packages
* Fix check for IPv6 enabled on host
## 3.0.0b3 19/05/2024 ## 3.0.0b3 19/05/2024
* Bundle web-ui v3.0.0b3 * Bundle web-ui v3.0.0b3

View File

@ -1,7 +1,7 @@
pytest==8.1.1 pytest==8.3.2
flake8==7.0.0 flake8==7.1.0
pytest-timeout==2.3.1 pytest-timeout==2.3.1
pytest-asyncio==0.21.1 pytest-asyncio==0.21.2
requests==2.31.0 requests==2.32.3
httpx==0.24.1 # version 0.24.1 is required by httpx_ws httpx==0.24.1 # version 0.24.1 is required by httpx_ws
httpx_ws==0.4.2 httpx_ws==0.4.2

View File

@ -320,6 +320,7 @@ async def export_project(
include_snapshots: bool = False, include_snapshots: bool = False,
include_images: bool = False, include_images: bool = False,
reset_mac_addresses: bool = False, reset_mac_addresses: bool = False,
keep_compute_ids: bool = False,
compression: schemas.ProjectCompression = "zstd", compression: schemas.ProjectCompression = "zstd",
compression_level: int = None, compression_level: int = None,
) -> StreamingResponse: ) -> StreamingResponse:
@ -366,6 +367,7 @@ async def export_project(
tmpdir, tmpdir,
include_snapshots=include_snapshots, include_snapshots=include_snapshots,
include_images=include_images, include_images=include_images,
keep_compute_ids=keep_compute_ids,
reset_mac_addresses=reset_mac_addresses, reset_mac_addresses=reset_mac_addresses,
) )
async for chunk in zstream: async for chunk in zstream:

View File

@ -32,6 +32,27 @@
"process_priority": "normal" "process_priority": "normal"
}, },
"images": [ "images": [
{
"filename": "arubaoscx-disk-image-genericx86-p4-20240129204649.vmdk",
"version": "10.13.1000",
"md5sum": "a1a24b15e3b8a09b0c0f14bdfacc4a75",
"filesize": 395342848,
"download_url": "https://networkingsupport.hpe.com"
},
{
"filename": "arubaoscx-disk-image-genericx86-p4-20231110145644.vmdk",
"version": "10.13.0005",
"md5sum": "427fd4580e2ee3eac55a9e7d629d1375",
"filesize": 394995200,
"download_url": "https://networkingsupport.hpe.com"
},
{
"filename": "arubaoscx-disk-image-genericx86-p4-20230810165021.vmdk",
"version": "10.12.1000",
"md5sum": "ea89f94dda9d28bf583dc35e0299b106",
"filesize": 384622080,
"download_url": "https://networkingsupport.hpe.com"
},
{ {
"filename": "arubaoscx-disk-image-genericx86-p4-20230531220439.vmdk", "filename": "arubaoscx-disk-image-genericx86-p4-20230531220439.vmdk",
"version": "10.12.0006", "version": "10.12.0006",
@ -118,6 +139,24 @@
} }
], ],
"versions": [ "versions": [
{
"name": "10.13.1000",
"images": {
"hda_disk_image": "arubaoscx-disk-image-genericx86-p4-20240129204649.vmdk"
}
},
{
"name": "10.13.0005",
"images": {
"hda_disk_image": "arubaoscx-disk-image-genericx86-p4-20231110145644.vmdk"
}
},
{
"name": "10.12.1000",
"images": {
"hda_disk_image": "arubaoscx-disk-image-genericx86-p4-20230810165021.vmdk"
}
},
{ {
"name": "10.12.0006", "name": "10.12.0006",
"images": { "images": {

View File

@ -19,7 +19,7 @@
}, },
"images": [ "images": [
{ {
"filename": "x86_64_crb_linux_l2-adventerprisek9-ms", "filename": "x86_64_crb_linux_l2-adventerprisek9-ms.bin",
"version": "17.12.1", "version": "17.12.1",
"md5sum": "2b5055e4cef8fd257416d74a94adb626", "md5sum": "2b5055e4cef8fd257416d74a94adb626",
"filesize": 240355720 "filesize": 240355720
@ -47,7 +47,7 @@
{ {
"name": "17.12.1", "name": "17.12.1",
"images": { "images": {
"image": "x86_64_crb_linux_l2-adventerprisek9-ms" "image": "x86_64_crb_linux_l2-adventerprisek9-ms.bin"
} }
}, },
{ {

View File

@ -19,7 +19,7 @@
}, },
"images": [ "images": [
{ {
"filename": "x86_64_crb_linux-adventerprisek9-ms", "filename": "x86_64_crb_linux-adventerprisek9-ms.bin",
"version": "17.12.1", "version": "17.12.1",
"md5sum": "4a2fce8de21d1831fbceffd155e41ae7", "md5sum": "4a2fce8de21d1831fbceffd155e41ae7",
"filesize": 288947184 "filesize": 288947184
@ -47,7 +47,7 @@
{ {
"name": "17.12.1", "name": "17.12.1",
"images": { "images": {
"image": "x86_64_crb_linux-adventerprisek9-ms" "image": "x86_64_crb_linux-adventerprisek9-ms.bin"
} }
}, },
{ {

View File

@ -23,6 +23,14 @@
"kvm": "allow" "kvm": "allow"
}, },
"images": [ "images": [
{
"filename": "debian-12.6.qcow2",
"version": "12.6",
"md5sum": "04753ba14295c6414d49bffe27b676ae",
"filesize": 280907776,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "https://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/debian-12.6.qcow2"
},
{ {
"filename": "debian-12.4.qcow2", "filename": "debian-12.4.qcow2",
"version": "12.4", "version": "12.4",
@ -31,6 +39,14 @@
"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/debian-12.4.qcow2" "direct_download_url": "https://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/debian-12.4.qcow2"
}, },
{
"filename": "debian-11.10.qcow2",
"version": "11.10",
"md5sum": "99a1dc8e110d641309674e69b630e732",
"filesize": 263520256,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "https://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/debian-11.10.qcow2"
},
{ {
"filename": "debian-11.8.qcow2", "filename": "debian-11.8.qcow2",
"version": "11.8", "version": "11.8",
@ -41,12 +57,24 @@
} }
], ],
"versions": [ "versions": [
{
"name": "12.6",
"images": {
"hda_disk_image": "debian-12.6.qcow2"
}
},
{ {
"name": "12.4", "name": "12.4",
"images": { "images": {
"hda_disk_image": "debian-12.4.qcow2" "hda_disk_image": "debian-12.4.qcow2"
} }
}, },
{
"name": "11.10",
"images": {
"hda_disk_image": "debian-11.10.qcow2"
}
},
{ {
"name": "11.8", "name": "11.8",
"images": { "images": {

View File

@ -28,10 +28,17 @@
}, },
"images": [ "images": [
{ {
"filename": "FAD_KVM-FORTINET.out.kvm-data.qcow2", "filename": "FAD_KVM-V7.4.4-build0347-FORTINET.out.kvm_boot.qcow2",
"version": "ALL", "version": "7.4.4",
"md5sum": "b7500835594e62d8acb1c6ec43d597c1", "md5sum": "52fa343fd423a1a560473b8cf02f4c9c",
"filesize": 30998528, "filesize": 180617216,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAD_KVM-V7.2.6-build0257-FORTINET.out.kvm_boot.qcow2",
"version": "7.2.6",
"md5sum": "ed8c3622b12212786c310aa94c928f06",
"filesize": 146341888,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx" "download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
}, },
{ {
@ -41,6 +48,13 @@
"filesize": 145817600, "filesize": 145817600,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx" "download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
}, },
{
"filename": "FAD_KVM-v7.1.4-build0138-FORTINET.out.kvm_boot.qcow2",
"version": "7.1.4",
"md5sum": "d4b3ff27fc9d0461199d6066174744ca",
"filesize": 134152192,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{ {
"filename": "FAD_KVM-V7.1.1-build0117-FORTINET.out.kvm-boot.qcow2", "filename": "FAD_KVM-V7.1.1-build0117-FORTINET.out.kvm-boot.qcow2",
"version": "7.1.1", "version": "7.1.1",
@ -243,9 +257,30 @@
"md5sum": "7a71f52bde93c0000b047626731b7aef", "md5sum": "7a71f52bde93c0000b047626731b7aef",
"filesize": 68026368, "filesize": 68026368,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx" "download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAD_KVM-FORTINET.out.kvm-data.qcow2",
"version": "ALL",
"md5sum": "b7500835594e62d8acb1c6ec43d597c1",
"filesize": 30998528,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
} }
], ],
"versions": [ "versions": [
{
"name": "7.4.4",
"images": {
"hda_disk_image": "FAD_KVM-V7.4.4-build0347-FORTINET.out.kvm_boot.qcow2",
"hdb_disk_image": "FAD_KVM-FORTINET.out.kvm-data.qcow2"
}
},
{
"name": "7.2.6",
"images": {
"hda_disk_image": "FAD_KVM-V7.2.6-build0257-FORTINET.out.kvm_boot.qcow2",
"hdb_disk_image": "FAD_KVM-FORTINET.out.kvm-data.qcow2"
}
},
{ {
"name": "7.2.0", "name": "7.2.0",
"images": { "images": {
@ -253,6 +288,13 @@
"hdb_disk_image": "FAD_KVM-FORTINET.out.kvm-data.qcow2" "hdb_disk_image": "FAD_KVM-FORTINET.out.kvm-data.qcow2"
} }
}, },
{
"name": "7.1.4",
"images": {
"hda_disk_image": "FAD_KVM-v7.1.4-build0138-FORTINET.out.kvm_boot.qcow2",
"hdb_disk_image": "FAD_KVM-FORTINET.out.kvm-data.qcow2"
}
},
{ {
"name": "7.1.1", "name": "7.1.1",
"images": { "images": {

View File

@ -29,6 +29,13 @@
"kvm": "allow" "kvm": "allow"
}, },
"images": [ "images": [
{
"filename": "FAZ_VM64_KVM-v7.4.3-build2487-FORTINET.out.kvm.qcow2",
"version": "7.4.3",
"md5sum": "c58709af18516763ed88f58621447bf6",
"filesize": 504463360,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{ {
"filename": "FAZ_VM64_KVM-v7.4.2-build2397-FORTINET.out.kvm.qcow2", "filename": "FAZ_VM64_KVM-v7.4.2-build2397-FORTINET.out.kvm.qcow2",
"version": "7.4.2", "version": "7.4.2",
@ -43,6 +50,13 @@
"filesize": 435310592, "filesize": 435310592,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx" "download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
}, },
{
"filename": "FAZ_VM64_KVM-v7.2.5-build1574-FORTINET.out.kvm.qcow2",
"version": "7.2.5",
"md5sum": "225d7405f35f78a482cffa34ef90080d",
"filesize": 379973632,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{ {
"filename": "FAZ_VM64_KVM-v7.2.4-build1460-FORTINET.out.kvm.qcow2", "filename": "FAZ_VM64_KVM-v7.2.4-build1460-FORTINET.out.kvm.qcow2",
"version": "7.2.4", "version": "7.2.4",
@ -64,6 +78,13 @@
"filesize": 340631552, "filesize": 340631552,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx" "download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
}, },
{
"filename": "FAZ_VM64_KVM-v7.0.12-build0623-FORTINET.out.kvm.qcow2",
"version": "7.0.12",
"md5sum": "a45f8987ea13da836c684b5d9850c1c2",
"filesize": 349560832,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{ {
"filename": "FAZ_VM64_KVM-v7.0.11-build0595-FORTINET.out.kvm.qcow2", "filename": "FAZ_VM64_KVM-v7.0.11-build0595-FORTINET.out.kvm.qcow2",
"version": "7.0.11", "version": "7.0.11",
@ -256,6 +277,13 @@
} }
], ],
"versions": [ "versions": [
{
"name": "7.4.3",
"images": {
"hda_disk_image": "FAZ_VM64_KVM-v7.4.3-build2487-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{ {
"name": "7.4.2", "name": "7.4.2",
"images": { "images": {
@ -270,6 +298,13 @@
"hdb_disk_image": "empty30G.qcow2" "hdb_disk_image": "empty30G.qcow2"
} }
}, },
{
"name": "7.2.5",
"images": {
"hda_disk_image": "FAZ_VM64_KVM-v7.2.5-build1574-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{ {
"name": "7.2.4", "name": "7.2.4",
"images": { "images": {
@ -291,6 +326,13 @@
"hdb_disk_image": "empty30G.qcow2" "hdb_disk_image": "empty30G.qcow2"
} }
}, },
{
"name": "7.0.12",
"images": {
"hda_disk_image": "FAZ_VM64_KVM-v7.0.12-build0623-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{ {
"name": "7.0.11", "name": "7.0.11",
"images": { "images": {

View File

@ -13,13 +13,13 @@
"status": "stable", "status": "stable",
"maintainer": "GNS3 Team", "maintainer": "GNS3 Team",
"maintainer_email": "developers@gns3.net", "maintainer_email": "developers@gns3.net",
"usage": "Default username is admin, no password is set. First book takes longer.", "usage": "Default username is admin, no password is set. First boot takes longer.",
"symbol": "fortinet.svg", "symbol": "fortinet.svg",
"port_name_format": "Port{port1}", "port_name_format": "Port{port1}",
"qemu": { "qemu": {
"adapter_type": "e1000", "adapter_type": "e1000",
"adapters": 4, "adapters": 4,
"ram": 1024, "ram": 4096,
"hda_disk_interface": "virtio", "hda_disk_interface": "virtio",
"hdb_disk_interface": "virtio", "hdb_disk_interface": "virtio",
"arch": "x86_64", "arch": "x86_64",
@ -28,6 +28,27 @@
"kvm": "allow" "kvm": "allow"
}, },
"images": [ "images": [
{
"filename": "FAC_VM_KVM-v6.6.1-build1660-FORTINET.out.kvm_fackvm.qcow2",
"version": "6.6.1",
"md5sum": "4b2b475ac8b6f88b5033dca367d53cbb",
"filesize": 138477584,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAC_VM_KVM-v6.5.5-build1385-FORTINET.out.kvm_fackvm.qcow2",
"version": "6.5.5",
"md5sum": "6850128ac51cee2577114ecd487786ff",
"filesize": 112918544,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAC_VM_KVM-v6.4.9-build1067-FORTINET.out.kvm_fackvm.qcow2",
"version": "6.4.9",
"md5sum": "aee068a16fb2ca332d41e6add499b7d3",
"filesize": 112197648,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{ {
"filename": "FAC_VM_KVM-v6-build0058-FORTINET.out.kvm.qcow2", "filename": "FAC_VM_KVM-v6-build0058-FORTINET.out.kvm.qcow2",
"version": "6.0.3", "version": "6.0.3",
@ -105,6 +126,20 @@
"filesize": 62771200, "filesize": 62771200,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx" "download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
}, },
{
"filename": "FAC_VM_KVM-v6.6.1-build1660-FORTINET.out.kvm_datadrive.qcow2",
"version": "6.6.1",
"md5sum": "9bbaa1ce1508b4af1f43ba00879269f9",
"filesize": 197568,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAC_VM_KVM-v6.5.5-build1385-FORTINET.out.kvm_datadrive.qcow2",
"version": "6.4.x, 6.5.x",
"md5sum": "3f7173307047cf562f55ed2f99450c10",
"filesize": 197568,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{ {
"filename": "FAC_VM_KVM-ALL-DATADRIVE.qcow2", "filename": "FAC_VM_KVM-ALL-DATADRIVE.qcow2",
"version": "All", "version": "All",
@ -114,6 +149,27 @@
} }
], ],
"versions": [ "versions": [
{
"name": "6.6.1",
"images": {
"hda_disk_image": "FAC_VM_KVM-v6.6.1-build1660-FORTINET.out.kvm_fackvm.qcow2",
"hdb_disk_image": "FAC_VM_KVM-v6.6.1-build1660-FORTINET.out.kvm_datadrive.qcow2"
}
},
{
"name": "6.5.5",
"images": {
"hda_disk_image": "FAC_VM_KVM-v6.5.5-build1385-FORTINET.out.kvm_fackvm.qcow2",
"hdb_disk_image": "FAC_VM_KVM-v6.5.5-build1385-FORTINET.out.kvm_datadrive.qcow2"
}
},
{
"name": "6.4.9",
"images": {
"hda_disk_image": "FAC_VM_KVM-v6.4.9-build1067-FORTINET.out.kvm_fackvm.qcow2",
"hdb_disk_image": "FAC_VM_KVM-v6.5.5-build1385-FORTINET.out.kvm_datadrive.qcow2"
}
},
{ {
"name": "6.0.3", "name": "6.0.3",
"images": { "images": {

View File

@ -28,6 +28,13 @@
"kvm": "allow" "kvm": "allow"
}, },
"images": [ "images": [
{
"filename": "FGT_VM64_KVM-v7.4.4.F-build2573-FORTINET.out.kvm.qcow2",
"version": "7.4.4",
"md5sum": "dfe0e78827ec728631539669001bb23f",
"filesize": 100728832,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{ {
"filename": "FGT_VM64_KVM-v7.4.3.F-build2573-FORTINET.out.kvm.qcow2", "filename": "FGT_VM64_KVM-v7.4.3.F-build2573-FORTINET.out.kvm.qcow2",
"version": "7.4.3", "version": "7.4.3",
@ -42,6 +49,13 @@
"filesize": 116064256, "filesize": 116064256,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx" "download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
}, },
{
"filename": "FGT_VM64_KVM-v7.2.8.M-build1639-FORTINET.out.kvm_fortios.qcow2",
"version": "7.2.8",
"md5sum": "5c8fd4baf80aeb2999d4be5a9c49eb3d",
"filesize": 89980928,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{ {
"filename": "FGT_VM64_KVM-v7.2.7.M-build1577-FORTINET.out.kvm.qcow2", "filename": "FGT_VM64_KVM-v7.2.7.M-build1577-FORTINET.out.kvm.qcow2",
"version": "7.2.7", "version": "7.2.7",
@ -77,6 +91,13 @@
"filesize": 86704128, "filesize": 86704128,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx" "download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
}, },
{
"filename": "FGT_VM64_KVM-v7.0.15.M-build0601-FORTINET.out.kvm.qcow2",
"version": "7.0.15",
"md5sum": "423f50378b7e93098ab765c3dd3a788f",
"filesize": 77398016,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{ {
"filename": "FGT_VM64_KVM-v7.0.14.M-build0601-FORTINET.out.kvm.qcow2", "filename": "FGT_VM64_KVM-v7.0.14.M-build0601-FORTINET.out.kvm.qcow2",
"version": "7.0.14", "version": "7.0.14",
@ -367,6 +388,13 @@
} }
], ],
"versions": [ "versions": [
{
"name": "7.4.4",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v7.4.4.F-build2573-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{ {
"name": "7.4.3", "name": "7.4.3",
"images": { "images": {
@ -381,6 +409,13 @@
"hdb_disk_image": "empty30G.qcow2" "hdb_disk_image": "empty30G.qcow2"
} }
}, },
{
"name": "7.2.8",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v7.2.8.M-build1639-FORTINET.out.kvm_fortios.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{ {
"name": "7.2.7", "name": "7.2.7",
"images": { "images": {
@ -416,6 +451,13 @@
"hdb_disk_image": "empty30G.qcow2" "hdb_disk_image": "empty30G.qcow2"
} }
}, },
{
"name": "7.0.15",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v7.0.15.M-build0601-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{ {
"name": "7.0.14", "name": "7.0.14",
"images": { "images": {

View File

@ -29,6 +29,13 @@
"kvm": "allow" "kvm": "allow"
}, },
"images": [ "images": [
{
"filename": "FMG_VM64_KVM-v7.4.3-build2487-FORTINET.out.kvm.qcow2",
"version": "7.4.23",
"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", "filename": "FMG_VM64_KVM-v7.4.2-build2397-FORTINET.out.kvm.qcow2",
"version": "7.4.2", "version": "7.4.2",
@ -43,6 +50,13 @@
"filesize": 309387264, "filesize": 309387264,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx" "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", "filename": "FMG_VM64_KVM-v7.2.4-build1460-FORTINET.out.kvm.qcow2",
"version": "7.2.4", "version": "7.2.4",
@ -64,6 +78,13 @@
"filesize": 242814976, "filesize": 242814976,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx" "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", "filename": "FMG_VM64_KVM-v7.0.11-build0595-FORTINET.out.kvm.qcow2",
"version": "7.0.11", "version": "7.0.11",
@ -256,6 +277,13 @@
} }
], ],
"versions": [ "versions": [
{
"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", "name": "7.4.2",
"images": { "images": {
@ -270,6 +298,13 @@
"hdb_disk_image": "empty30G.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", "name": "7.2.4",
"images": { "images": {
@ -291,6 +326,13 @@
"hdb_disk_image": "empty30G.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", "name": "7.0.11",
"images": { "images": {

View File

@ -28,6 +28,27 @@
"kvm": "allow" "kvm": "allow"
}, },
"images": [ "images": [
{
"filename": "FWB_KVM-v7.6.0.F-build0962-FORTINET.out.kvm_boot.qcow2",
"version": "7.6.0",
"md5sum": "e94aa4af7ed0a12bd6084f0d74a2a96e",
"filesize": 329187840,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FWB_KVM-v7.4.3-build0638-FORTINET.out.kvm_boot.qcow2",
"version": "7.4.3",
"md5sum": "3c0ac11a6d80a319a4fe460aff5bc66c",
"filesize": 303497728,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FWB_KVM-v7.2.8-build0400-FORTINET.out.kvm_boot.qcow2",
"version": "7.2.8",
"md5sum": "367307242e6855dc190df089d196e712",
"filesize": 257950208,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{ {
"filename": "FWB_KVM-v7.2.1-build0330-FORTINET.out.kvm.boot.qcow2", "filename": "FWB_KVM-v7.2.1-build0330-FORTINET.out.kvm.boot.qcow2",
"version": "7.2.1", "version": "7.2.1",
@ -35,6 +56,13 @@
"filesize": 260506112, "filesize": 260506112,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx" "download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
}, },
{
"filename": "FWB_KVM-v7.0.10-build0166-FORTINET.out.kvm_boot.qcow2",
"version": "7.0.10",
"md5sum": "ff9d4b827c4e41c1b38e59359ba05487",
"filesize": 257556992,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{ {
"filename": "FWB_KVM-v7.0.6-build0140-FORTINET.out.kvm.boot.qcow2", "filename": "FWB_KVM-v7.0.6-build0140-FORTINET.out.kvm.boot.qcow2",
"version": "7.0.6", "version": "7.0.6",
@ -150,6 +178,27 @@
} }
], ],
"versions": [ "versions": [
{
"name": "7.6.0",
"images": {
"hda_disk_image": "FWB_KVM-v7.6.0.F-build0962-FORTINET.out.kvm_boot.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.4.3",
"images": {
"hda_disk_image": "FWB_KVM-v7.4.3-build0638-FORTINET.out.kvm_boot.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.8",
"images": {
"hda_disk_image": "FWB_KVM-v7.2.8-build0400-FORTINET.out.kvm_boot.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{ {
"name": "7.2.1", "name": "7.2.1",
"images": { "images": {
@ -157,6 +206,13 @@
"hdb_disk_image": "empty30G.qcow2" "hdb_disk_image": "empty30G.qcow2"
} }
}, },
{
"name": "7.0.10",
"images": {
"hda_disk_image": "FWB_KVM-v7.0.10-build0166-FORTINET.out.kvm_boot.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{ {
"name": "7.0.6", "name": "7.0.6",
"images": { "images": {

View File

@ -12,18 +12,19 @@
"status": "stable", "status": "stable",
"maintainer": "GNS3 Team", "maintainer": "GNS3 Team",
"maintainer_email": "developers@gns3.net", "maintainer_email": "developers@gns3.net",
"usage": "16 GB RAM is the bare minimum; you should use 32/64 GB in production deplyments.\nDefault credentials:\n- CLI: admin / abc123\n- WebUI: super / juniper123", "usage": "16 GB RAM is the bare minimum; you should use 32/64 GB in production deployments.\nDefault credentials:\n- CLI: admin / abc123\n- WebUI: super / juniper123",
"symbol": "juniper-vqfx.svg", "symbol": "juniper-vqfx.svg",
"port_name_format": "em{0}", "port_name_format": "em{0}",
"qemu": { "qemu": {
"adapter_type": "e1000", "adapter_type": "e1000",
"adapters": 4, "adapters": 4,
"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": "-smp 4 -nographic" "options": "-nographic -machine q35,smbios-entry-point-type=32"
}, },
"images": [ "images": [
{ {

View File

@ -34,7 +34,7 @@
"arch": "x86_64", "arch": "x86_64",
"console_type": "telnet", "console_type": "telnet",
"kvm": "require", "kvm": "require",
"options": "-nographic" "options": "-nographic -machine q35,smbios-entry-point-type=32"
}, },
"images": [ "images": [
{ {

View File

@ -26,7 +26,7 @@
"arch": "x86_64", "arch": "x86_64",
"console_type": "telnet", "console_type": "telnet",
"kvm": "require", "kvm": "require",
"options": "-nographic -enable-kvm" "options": "-nographic -enable-kvm -machine q35,smbios-entry-point-type=32"
}, },
"images": [ "images": [
{ {

View File

@ -20,11 +20,12 @@
"adapter_type": "virtio-net-pci", "adapter_type": "virtio-net-pci",
"adapters": 13, "adapters": 13,
"ram": 4096, "ram": 4096,
"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": "-nographic -enable-kvm -smp cpus=3" "options": "-nographic -enable-kvm -machine q35,smbios-entry-point-type=32"
}, },
"images": [ "images": [
{ {

View File

@ -23,7 +23,7 @@
"arch": "x86_64", "arch": "x86_64",
"console_type": "vnc", "console_type": "vnc",
"kvm": "require", "kvm": "require",
"options": "-nographic" "options": "-nographic -machine q35,smbios-entry-point-type=32"
}, },
"images": [ "images": [
{ {

View File

@ -19,11 +19,12 @@
"adapter_type": "virtio-net-pci", "adapter_type": "virtio-net-pci",
"adapters": 12, "adapters": 12,
"ram": 1024, "ram": 1024,
"cpus": 2,
"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": "-nographic -smp 2" "options": "-nographic -machine q35,smbios-entry-point-type=32"
}, },
"images": [ "images": [
{ {

View File

@ -25,7 +25,7 @@
"arch": "x86_64", "arch": "x86_64",
"console_type": "telnet", "console_type": "telnet",
"kvm": "require", "kvm": "require",
"options": "-nographic -enable-kvm" "options": "-nographic -enable-kvm -machine q35,smbios-entry-point-type=32"
}, },
"images": [ "images": [
{ {

View File

@ -19,11 +19,12 @@
"adapter_type": "vmxnet3", "adapter_type": "vmxnet3",
"adapters": 6, "adapters": 6,
"ram": 4096, "ram": 4096,
"cpus": 2,
"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": "-smp 2" "options": "-machine q35,smbios-entry-point-type=32"
}, },
"images": [ "images": [
{ {

View File

@ -28,6 +28,20 @@
}, },
"images": [ "images": [
{ {
"filename": "PA-VM-KVM-11.0.0.qcow2",
"version": "11.0.0",
"md5sum": "fc54b0e680ca2bcecb5522430e420f06",
"filesize": 4130865152,
"download_url": "https://support.paloaltonetworks.com/Updates/SoftwareUpdates/"
},
{
"filename": "PA-VM-KVM-10.2.3.qcow2",
"version": "10.2.3",
"md5sum": "0e7b2a52d1447186d335ef9a1a197c6c",
"filesize": 5298585600,
"download_url": "https://support.paloaltonetworks.com/Updates/SoftwareUpdates/"
},
{
"filename": "PA-VM-KVM-10.1.0.qcow2", "filename": "PA-VM-KVM-10.1.0.qcow2",
"version": "10.1.0", "version": "10.1.0",
"md5sum": "8266fd412a22694749f2cd4afcd5fa33", "md5sum": "8266fd412a22694749f2cd4afcd5fa33",
@ -127,6 +141,18 @@
} }
], ],
"versions": [ "versions": [
{
"name": "11.0.0",
"images": {
"hda_disk_image": "PA-VM-KVM-11.0.0.qcow2"
}
},
{
"name": "10.2.3",
"images": {
"hda_disk_image": "PA-VM-KVM-10.2.3.qcow2"
}
},
{ {
"name": "10.1.0", "name": "10.1.0",
"images": { "images": {

View File

@ -13,18 +13,27 @@
"status": "stable", "status": "stable",
"maintainer": "Brent Stewart", "maintainer": "Brent Stewart",
"maintainer_email": "brent@stewart.tc", "maintainer_email": "brent@stewart.tc",
"usage": "Your default account will have sudo priviledges. Squil and Squert username and password are configured in the Setup wizard. MySQL root is set to null. For more info see https://github.com/Security-Onion-Solutions/security-onion/wiki/Passwords.", "usage": "Your default account will have sudo privileges. Squil and Squert username and password are configured in the Setup wizard. MySQL root is set to null. For more info see https://github.com/Security-Onion-Solutions/security-onion/wiki/Passwords.",
"symbol": "securityonion-logo.png", "symbol": "securityonion-logo.png",
"qemu": { "qemu": {
"adapter_type": "e1000", "adapter_type": "e1000",
"adapters": 2, "adapters": 2,
"ram": 3072, "ram": 4096,
"hda_disk_interface": "ide", "hda_disk_interface": "ide",
"arch": "x86_64", "arch": "x86_64",
"console_type": "vnc", "console_type": "vnc",
"kvm": "allow" "kvm": "allow",
"options": "-cpu host"
}, },
"images": [ "images": [
{
"filename": "securityonion-2.4.80-20240624.iso",
"version": "2.4.80-20240624",
"md5sum": "139f9762e926f9cb3c4a9528a3752c31",
"filesize": 12391022592,
"download_url": "https://github.com/Security-Onion-Solutions/securityonion/blob/2.4/main/DOWNLOAD_AND_VERIFY_ISO.md",
"direct_download_url": "https://download.securityonion.net/file/securityonion/securityonion-2.4.80-20240624.iso"
},
{ {
"filename": "securityonion-16.04.7.1.iso", "filename": "securityonion-16.04.7.1.iso",
"version": "16.04.7.1", "version": "16.04.7.1",
@ -49,6 +58,14 @@
"download_url": "https://github.com/Security-Onion-Solutions/security-onion/releases/", "download_url": "https://github.com/Security-Onion-Solutions/security-onion/releases/",
"direct_download_url": "https://github.com/Security-Onion-Solutions/security-onion/releases/download/v14.04.5.4_20171031/securityonion-14.04.5.4.iso" "direct_download_url": "https://github.com/Security-Onion-Solutions/security-onion/releases/download/v14.04.5.4_20171031/securityonion-14.04.5.4.iso"
}, },
{
"filename": "empty100G.qcow2",
"version": "1.0",
"md5sum": "5d9fec18a980f13002028491259f158d",
"filesize": 198656,
"download_url": "https://github.com/riverbed/Riverbed-Community-Toolkit/raw/master/SteelHead/GNS3",
"direct_download_url": "https://github.com/riverbed/Riverbed-Community-Toolkit/raw/master/SteelHead/GNS3/empty100G.qcow2"
},
{ {
"filename": "empty30G.qcow2", "filename": "empty30G.qcow2",
"version": "1.0", "version": "1.0",
@ -59,6 +76,13 @@
} }
], ],
"versions": [ "versions": [
{
"name": "2.4.80-20240624",
"images": {
"hda_disk_image": "empty100G.qcow2",
"cdrom_image": "securityonion-2.4.80-20240624.iso"
}
},
{ {
"name": "16.04.7.1", "name": "16.04.7.1",
"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:focal", "image": "gns3/ubuntu:noble",
"console_type": "telnet" "console_type": "telnet"
} }
} }

View File

@ -28,6 +28,7 @@ import shutil
import platformdirs import platformdirs
from gns3server.utils import parse_version from gns3server.utils import parse_version
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
@ -95,8 +96,13 @@ class Docker(BaseManager):
Get the Docker resources storage directory Get the Docker resources storage directory
""" """
resources_path = Config.instance().settings.Server.resources_path
if not resources_path:
appname = vendor = "GNS3" appname = vendor = "GNS3"
docker_resources_dir = os.path.join(platformdirs.user_data_dir(appname, vendor, roaming=True), "docker", "resources") resources_path = platformdirs.user_data_dir(appname, vendor, roaming=True)
else:
resources_path = os.path.expanduser(resources_path)
docker_resources_dir = os.path.join(resources_path, "docker")
os.makedirs(docker_resources_dir, exist_ok=True) os.makedirs(docker_resources_dir, exist_ok=True)
return docker_resources_dir return docker_resources_dir

View File

@ -45,7 +45,7 @@ from ..nios.nio_tap import NIOTAP
from ..base_node import BaseNode from ..base_node import BaseNode
from ...utils.asyncio import monitor_process from ...utils.asyncio import monitor_process
from ...utils.images import md5sum from ...utils.images import md5sum
from ...utils import macaddress_to_int, int_to_macaddress from ...utils import macaddress_to_int, int_to_macaddress, is_ipv6_enabled
from ...utils.hostname import is_rfc1123_hostname_valid from ...utils.hostname import is_rfc1123_hostname_valid
from gns3server.schemas.compute.qemu_nodes import Qemu, QemuPlatform from gns3server.schemas.compute.qemu_nodes import Qemu, QemuPlatform
@ -54,6 +54,12 @@ import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# forbidden additional options
FORBIDDEN_OPTIONS = {"-blockdev", "-drive", "-hda", "-hdb", "-hdc", "-hdd",
"-fsdev", "-virtfs", "-nic", "-netdev"}
FORBIDDEN_OPTIONS |= {"-" + opt for opt in FORBIDDEN_OPTIONS
if opt.startswith("-") and not opt.startswith("--")}
class QemuVM(BaseNode): class QemuVM(BaseNode):
module_name = "qemu" module_name = "qemu"
@ -1855,14 +1861,17 @@ class QemuVM(BaseNode):
if port: if port:
console_host = self._manager.port_manager.console_host console_host = self._manager.port_manager.console_host
if console_host == "0.0.0.0": if console_host == "0.0.0.0":
if socket.has_ipv6: try:
if is_ipv6_enabled():
# to fix an issue with Qemu when IPv4 is not enabled # to fix an issue with Qemu when IPv4 is not enabled
# see https://github.com/GNS3/gns3-gui/issues/2352 # see https://github.com/GNS3/gns3-gui/issues/2352
# FIXME: consider making this more global (not just for Qemu + SPICE) # FIXME: consider making this more global (not just for Qemu + SPICE)
console_host = "::" console_host = "::"
else: except OSError as e:
raise QemuError("IPv6 must be enabled in order to use the SPICE console") raise QemuError("Could not check if IPv6 is enabled: {}".format(e))
return ["-spice", f"addr={console_host},port={port},disable-ticketing", "-vga", "qxl"] return ["-spice",
f"addr={console_host},port={port},disable-ticketing",
"-vga", "qxl"]
else: else:
return [] return []
@ -2640,9 +2649,16 @@ class QemuVM(BaseNode):
command.extend(self._tpm_options()) command.extend(self._tpm_options())
if additional_options: if additional_options:
try: try:
command.extend(shlex.split(additional_options)) additional_opt_list = shlex.split(additional_options)
except ValueError as e: except ValueError as e:
raise QemuError(f"Invalid additional options: {additional_options} error {e}") raise QemuError(f"Invalid additional options: {additional_options} error {e}")
allow_unsafe_options = self.manager.config.settings.Qemu.allow_unsafe_options
if allow_unsafe_options is False:
for opt in additional_opt_list:
if opt in FORBIDDEN_OPTIONS:
raise QemuError("Forbidden additional option: {}".format(opt))
command.extend(additional_opt_list)
# avoiding mouse offset (see https://github.com/GNS3/gns3-server/issues/2335) # avoiding mouse offset (see https://github.com/GNS3/gns3-server/issues/2335)
if self._console_type == "vnc": if self._console_type == "vnc":
command.extend(['-machine', 'usb=on', '-device', 'usb-tablet']) command.extend(['-machine', 'usb=on', '-device', 'usb-tablet'])

View File

@ -34,7 +34,7 @@ enable_ssl = False
certfile = /home/gns3/.config/GNS3/ssl/server.cert certfile = /home/gns3/.config/GNS3/ssl/server.cert
certkey = /home/gns3/.config/GNS3/ssl/server.key certkey = /home/gns3/.config/GNS3/ssl/server.key
; Path where devices images are stored ; Path where binary images are stored
images_path = /home/gns3/GNS3/images images_path = /home/gns3/GNS3/images
; Additional paths to look for images ; Additional paths to look for images
@ -43,15 +43,20 @@ additional_images_paths = /opt/images;/mnt/disk1/images
; Path where user projects are stored ; Path where user projects are stored
projects_path = /home/gns3/GNS3/projects projects_path = /home/gns3/GNS3/projects
; Path where user appliances are stored ; Path where custom user appliances are stored
appliances_path = /home/gns3/GNS3/appliances appliances_path = /home/gns3/GNS3/appliances
; Path where custom device symbols are stored ; Path where custom user symbols are stored
symbols_path = /home/gns3/GNS3/symbols symbols_path = /home/gns3/GNS3/symbols
; Path where custom configs are stored ; Path where custom configs are stored
configs_path = /home/gns3/GNS3/configs configs_path = /home/gns3/GNS3/configs
; Path where files like built-in appliances and Docker resources are stored
; The default path is the local user data directory
; (Linux: "~/.local/share/GNS3", macOS: "~/Library/Application Support/GNS3", Windows: "%APPDATA%\GNS3")
; resources_path = /home/gns3/GNS3/resources
; Default symbol theme ; Default symbol theme
; Currently available themes are "Classic", Affinity-square-blue", "Affinity-square-red" ; Currently available themes are "Classic", Affinity-square-blue", "Affinity-square-red"
; "Affinity-square-gray", "Affinity-circle-blue", "Affinity-circle-red" and "Affinity-circle-gray" ; "Affinity-square-gray", "Affinity-circle-blue", "Affinity-circle-red" and "Affinity-circle-gray"
@ -102,6 +107,9 @@ default_nat_interface = vmnet10
; Enable the built-in templates ; Enable the built-in templates
enable_builtin_templates = True enable_builtin_templates = True
; Install built-in appliances
install_builtin_appliances = True
; check if hardware virtualization is used by other emulators (KVM, VMware or VirtualBox) ; check if hardware virtualization is used by other emulators (KVM, VMware or VirtualBox)
hardware_virtualization_check = True hardware_virtualization_check = True
@ -148,3 +156,5 @@ monitor_host = 127.0.0.1
enable_hardware_acceleration = True enable_hardware_acceleration = True
; Require hardware acceleration in order to start VMs ; Require hardware acceleration in order to start VMs
require_hardware_acceleration = False require_hardware_acceleration = False
; Allow unsafe additional command line options
allow_unsafe_options = False

View File

@ -15,7 +15,7 @@ no ip icmp rate-limit unreachable
! !
! due to some bugs with IOU, try to change the following line to 'ip cef' if your routing does not work ! due to some bugs with IOU, try to change the following line to 'ip cef' if your routing does not work
no ip cef no ip cef
no ip domain-lookup no ip domain lookup
! !
! !
! !

View File

@ -14,7 +14,7 @@ no ip icmp rate-limit unreachable
! !
! due to some bugs with IOU, try to change the following line to 'ip cef' if your routing does not work ! due to some bugs with IOU, try to change the following line to 'ip cef' if your routing does not work
no ip cef no ip cef
no ip domain-lookup no ip domain lookup
! !
! !
ip tcp synwait-time 5 ip tcp synwait-time 5

View File

@ -270,13 +270,18 @@ class Controller:
log.error(f"Cannot read IOU license file '{iourc_path}': {e}") log.error(f"Cannot read IOU license file '{iourc_path}': {e}")
self._iou_license_settings["license_check"] = iou_config.license_check self._iou_license_settings["license_check"] = iou_config.license_check
# install the built-in appliances if needed
if Config.instance().settings.Server.install_builtin_appliances:
previous_version = controller_vars.get("version") previous_version = controller_vars.get("version")
log.info("Comparing controller version {} with config version {}".format(__version__, previous_version)) log.info("Comparing controller version {} with config version {}".format(__version__, previous_version))
builtin_appliances_path = self._appliance_manager.builtin_appliances_path()
if not previous_version or \ if not previous_version or \
parse_version(__version__.split("+")[0]) > parse_version(previous_version.split("+")[0]): parse_version(__version__.split("+")[0]) > parse_version(previous_version.split("+")[0]):
self._appliance_manager.install_builtin_appliances() self._appliance_manager.install_builtin_appliances()
elif not os.listdir(self._appliance_manager.builtin_appliances_path()): elif not os.listdir(builtin_appliances_path):
self._appliance_manager.install_builtin_appliances() self._appliance_manager.install_builtin_appliances()
else:
log.info(f"Built-in appliances are installed in '{builtin_appliances_path}'")
self._appliance_manager.appliances_etag = controller_vars.get("appliances_etag") self._appliance_manager.appliances_etag = controller_vars.get("appliances_etag")
self._appliance_manager.load_appliances() self._appliance_manager.load_appliances()

View File

@ -100,8 +100,13 @@ class ApplianceManager:
Get the built-in appliance storage directory Get the built-in appliance storage directory
""" """
resources_path = Config.instance().settings.Server.resources_path
if not resources_path:
appname = vendor = "GNS3" appname = vendor = "GNS3"
appliances_dir = os.path.join(platformdirs.user_data_dir(appname, vendor, roaming=True), "appliances") resources_path = platformdirs.user_data_dir(appname, vendor, roaming=True)
else:
resources_path = os.path.expanduser(resources_path)
appliances_dir = os.path.join(resources_path, "appliances")
if delete_first: if delete_first:
shutil.rmtree(appliances_dir, ignore_errors=True) shutil.rmtree(appliances_dir, ignore_errors=True)
os.makedirs(appliances_dir, exist_ok=True) os.makedirs(appliances_dir, exist_ok=True)

View File

@ -39,7 +39,7 @@ async def export_project(
temporary_dir, temporary_dir,
include_images=False, include_images=False,
include_snapshots=False, include_snapshots=False,
keep_compute_id=False, keep_compute_ids=False,
allow_all_nodes=False, allow_all_nodes=False,
reset_mac_addresses=False, reset_mac_addresses=False,
): ):
@ -54,9 +54,9 @@ async def export_project(
:param temporary_dir: A temporary dir where to store intermediate data :param temporary_dir: A temporary dir where to store intermediate data
:param include_images: save OS images to the zip file :param include_images: save OS images to the zip file
:param include_snapshots: save snapshots to the zip file :param include_snapshots: save snapshots to the zip file
:param keep_compute_id: If false replace all compute id by local (standard behavior for .gns3project to make it portable) :param keep_compute_ids: If false replace all compute IDs by local (standard behavior for .gns3project to make it portable)
:param allow_all_nodes: Allow all nodes type to be include in the zip even if not portable :param allow_all_nodes: Allow all nodes type to be included in the zip even if not portable
:param reset_mac_addresses: Reset MAC addresses for every nodes. :param reset_mac_addresses: Reset MAC addresses for each node.
""" """
# To avoid issue with data not saved we disallow the export of a running project # To avoid issue with data not saved we disallow the export of a running project
@ -77,7 +77,7 @@ async def export_project(
os.path.join(project._path, file), os.path.join(project._path, file),
zstream, zstream,
include_images, include_images,
keep_compute_id, keep_compute_ids,
allow_all_nodes, allow_all_nodes,
temporary_dir, temporary_dir,
reset_mac_addresses, reset_mac_addresses,
@ -193,7 +193,7 @@ def _is_exportable(path, include_snapshots=False):
async def _patch_project_file( async def _patch_project_file(
project, path, zstream, include_images, keep_compute_id, allow_all_nodes, temporary_dir, reset_mac_addresses project, path, zstream, include_images, keep_compute_ids, allow_all_nodes, temporary_dir, reset_mac_addresses
): ):
""" """
Patch a project file (.gns3) to export a project. Patch a project file (.gns3) to export a project.
@ -225,7 +225,7 @@ async def _patch_project_file(
if not allow_all_nodes and node["node_type"] in ["virtualbox", "vmware"]: if not allow_all_nodes and node["node_type"] in ["virtualbox", "vmware"]:
raise ControllerError("Projects with a {} node cannot be exported".format(node["node_type"])) raise ControllerError("Projects with a {} node cannot be exported".format(node["node_type"]))
if not keep_compute_id: if not keep_compute_ids:
node["compute_id"] = "local" # To make project portable all node by default run on local node["compute_id"] = "local" # To make project portable all node by default run on local
if "properties" in node and node["node_type"] != "docker": if "properties" in node and node["node_type"] != "docker":
@ -243,13 +243,13 @@ async def _patch_project_file(
if value is None or value.strip() == "": if value is None or value.strip() == "":
continue continue
if not keep_compute_id: # If we keep the original compute we can keep the image path if not keep_compute_ids: # If we keep the original compute we can keep the image path
node["properties"][prop] = os.path.basename(value) node["properties"][prop] = os.path.basename(value)
if include_images is True: if include_images is True:
images.append({"compute_id": compute_id, "image": value, "image_type": node["node_type"]}) images.append({"compute_id": compute_id, "image": value, "image_type": node["node_type"]})
if not keep_compute_id: if not keep_compute_ids:
topology["topology"][ topology["topology"][
"computes" "computes"
] = [] # Strip compute information because could contain secret info like password ] = [] # Strip compute information because could contain secret info like password

View File

@ -40,7 +40,7 @@ Handle the import of project from a .gns3project
""" """
async def import_project(controller, project_id, stream, location=None, name=None, keep_compute_id=False, async def import_project(controller, project_id, stream, location=None, name=None, keep_compute_ids=False,
auto_start=False, auto_open=False, auto_close=True): auto_start=False, auto_open=False, auto_close=True):
""" """
Import a project contain in a zip file Import a project contain in a zip file
@ -52,7 +52,7 @@ async def import_project(controller, project_id, stream, location=None, name=Non
:param stream: A io.BytesIO of the zipfile :param stream: A io.BytesIO of the zipfile
:param location: Directory for the project if None put in the default directory :param location: Directory for the project if None put in the default directory
:param name: Wanted project name, generate one from the .gns3 if None :param name: Wanted project name, generate one from the .gns3 if None
:param keep_compute_id: If true do not touch the compute id :param keep_compute_ids: keep compute IDs unchanged
:returns: Project :returns: Project
""" """
@ -126,7 +126,7 @@ async def import_project(controller, project_id, stream, location=None, name=Non
drawing["drawing_id"] = str(uuid.uuid4()) drawing["drawing_id"] = str(uuid.uuid4())
# Modify the compute id of the node depending of compute capacity # Modify the compute id of the node depending of compute capacity
if not keep_compute_id: if not keep_compute_ids:
# For some VM type we move them to the GNS3 VM if possible # For some VM type we move them to the GNS3 VM if possible
# unless it's a linux host without GNS3 VM # unless it's a linux host without GNS3 VM
if not sys.platform.startswith("linux") or controller.has_compute("vm"): if not sys.platform.startswith("linux") or controller.has_compute("vm"):

View File

@ -210,7 +210,11 @@ class Project:
if os.path.exists(snapshot_dir): if os.path.exists(snapshot_dir):
for snap in os.listdir(snapshot_dir): for snap in os.listdir(snapshot_dir):
if snap.endswith(".gns3project"): if snap.endswith(".gns3project"):
try:
snapshot = Snapshot(self, filename=snap) snapshot = Snapshot(self, filename=snap)
except ValueError:
log.error("Invalid snapshot file: {}".format(snap))
continue
self._snapshots[snapshot.id] = snapshot self._snapshots[snapshot.id] = snapshot
# Create the project on demand on the compute node # Create the project on demand on the compute node
@ -491,7 +495,7 @@ class Project:
if base_name is None: if base_name is None:
return None return None
base_name = re.sub(r"[ ]", "", base_name) base_name = re.sub(r"[ ]", "", base_name) # remove spaces in node name
if base_name in self._allocated_node_names: if base_name in self._allocated_node_names:
base_name = re.sub(r"[0-9]+$", "{0}", base_name) base_name = re.sub(r"[0-9]+$", "{0}", base_name)
@ -1087,7 +1091,7 @@ class Project:
zstream, zstream,
self, self,
tmpdir, tmpdir,
keep_compute_id=True, keep_compute_ids=True,
allow_all_nodes=True, allow_all_nodes=True,
reset_mac_addresses=reset_mac_addresses, reset_mac_addresses=reset_mac_addresses,
) )
@ -1106,7 +1110,7 @@ class Project:
str(uuid.uuid4()), str(uuid.uuid4()),
f, f,
name=name, name=name,
keep_compute_id=True keep_compute_ids=True
) )
log.info(f"Project '{project.name}' duplicated in {time.time() - begin:.4f} seconds") log.info(f"Project '{project.name}' duplicated in {time.time() - begin:.4f} seconds")

View File

@ -59,14 +59,9 @@ class Snapshot:
+ ".gns3project" + ".gns3project"
) )
else: else:
self._name = filename.split("_")[0] self._name = filename.rsplit("_", 2)[0]
datestring = filename.replace(self._name + "_", "").split(".")[0] datestring = filename.replace(self._name + "_", "").split(".")[0]
try: self._created_at = (datetime.strptime(datestring, "%d%m%y_%H%M%S").replace(tzinfo=timezone.utc).timestamp())
self._created_at = (
datetime.strptime(datestring, "%d%m%y_%H%M%S").replace(tzinfo=timezone.utc).timestamp()
)
except ValueError:
self._created_at = datetime.now(timezone.utc)
self._path = os.path.join(project.path, "snapshots", filename) self._path = os.path.join(project.path, "snapshots", filename)
@property @property
@ -104,7 +99,7 @@ class Snapshot:
with tempfile.TemporaryDirectory(dir=snapshot_directory) as tmpdir: with tempfile.TemporaryDirectory(dir=snapshot_directory) as tmpdir:
# Do not compress the snapshots # Do not compress the snapshots
with aiozipstream.ZipFile(compression=zipfile.ZIP_STORED) as zstream: with aiozipstream.ZipFile(compression=zipfile.ZIP_STORED) as zstream:
await export_project(zstream, self._project, tmpdir, keep_compute_id=True, allow_all_nodes=True) await export_project(zstream, self._project, tmpdir, keep_compute_ids=True, allow_all_nodes=True)
async with aiofiles.open(self.path, "wb") as f: async with aiofiles.open(self.path, "wb") as f:
async for chunk in zstream: async for chunk in zstream:
await f.write(chunk) await f.write(chunk)

View File

@ -35,6 +35,7 @@ from .drawing import Drawing
from .node import Node from .node import Node
from .link import Link from .link import Link
from gns3server.utils.hostname import is_ios_hostname_valid, is_rfc1123_hostname_valid, to_rfc1123_hostname, to_ios_hostname
from gns3server.schemas.controller.topology import Topology from gns3server.schemas.controller.topology import Topology
from gns3server.schemas.compute.dynamips_nodes import DynamipsCreate from gns3server.schemas.compute.dynamips_nodes import DynamipsCreate
@ -43,7 +44,7 @@ import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
GNS3_FILE_FORMAT_REVISION = 9 GNS3_FILE_FORMAT_REVISION = 10
class DynamipsNodeValidation(DynamipsCreate): class DynamipsNodeValidation(DynamipsCreate):
@ -186,6 +187,10 @@ def load_topology(path):
if variables: if variables:
topo["variables"] = [var for var in variables if var.get("name")] topo["variables"] = [var for var in variables if var.get("name")]
# Version before GNS3 3.0
if topo["revision"] < 10:
topo = _convert_2_2_0(topo, path)
try: try:
_check_topology_schema(topo, path) _check_topology_schema(topo, path)
except ControllerError as e: except ControllerError as e:
@ -201,6 +206,30 @@ def load_topology(path):
return topo return topo
def _convert_2_2_0(topo, topo_path):
"""
Convert topologies from GNS3 2.2.x to 3.0
Changes:
* Convert Qemu and Docker node names to be a valid RFC1123 hostnames.
* Convert Dynamips and IOU node names to be a valid IOS hostnames.
"""
topo["revision"] = 10
for node in topo.get("topology", {}).get("nodes", []):
if "properties" in node:
if node["node_type"] in ("qemu", "docker") and not is_rfc1123_hostname_valid(node["name"]):
new_name = to_rfc1123_hostname(node["name"])
log.info(f"Convert node name {node['name']} to {new_name} (RFC1123)")
node["name"] = new_name
if node["node_type"] in ("dynamips", "iou") and not is_ios_hostname_valid(node["name"] ):
new_name = to_ios_hostname(node["name"])
log.info(f"Convert node name {node['name']} to {new_name} (IOS)")
node["name"] = new_name
return topo
def _convert_2_1_0(topo, topo_path): def _convert_2_1_0(topo, topo_path):
""" """
Convert topologies from GNS3 2.1.x to 2.2 Convert topologies from GNS3 2.1.x to 2.2

View File

@ -58,7 +58,7 @@ class CrashReport:
Report crash to a third party service Report crash to a third party service
""" """
DSN = "https://99870c759d1c1d62ceb091d59dbcfa78@o19455.ingest.us.sentry.io/38482" DSN = "https://1ae6f3c9d64e75bf8ad39295723da722@o19455.ingest.us.sentry.io/38482"
_instance = None _instance = None
def __init__(self): def __init__(self):

View File

@ -69,6 +69,7 @@ class QemuSettings(BaseModel):
monitor_host: str = "127.0.0.1" monitor_host: str = "127.0.0.1"
enable_hardware_acceleration: bool = True enable_hardware_acceleration: bool = True
require_hardware_acceleration: bool = False require_hardware_acceleration: bool = False
allow_unsafe_options: bool = False
model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True) model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True)
@ -126,6 +127,7 @@ class ServerSettings(BaseModel):
appliances_path: str = "~/GNS3/appliances" appliances_path: str = "~/GNS3/appliances"
symbols_path: str = "~/GNS3/symbols" symbols_path: str = "~/GNS3/symbols"
configs_path: str = "~/GNS3/configs" configs_path: str = "~/GNS3/configs"
resources_path: str = None
default_symbol_theme: BuiltinSymbolTheme = BuiltinSymbolTheme.affinity_square_blue default_symbol_theme: BuiltinSymbolTheme = BuiltinSymbolTheme.affinity_square_blue
allow_raw_images: bool = True allow_raw_images: bool = True
auto_discover_images: bool = True auto_discover_images: bool = True
@ -144,6 +146,7 @@ class ServerSettings(BaseModel):
default_nat_interface: str = None default_nat_interface: str = None
allow_remote_console: bool = False allow_remote_console: bool = False
enable_builtin_templates: bool = True enable_builtin_templates: bool = True
install_builtin_appliances: bool = True
model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True, use_enum_values=True) model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True, use_enum_values=True)
@field_validator("additional_images_paths", mode="before") @field_validator("additional_images_paths", mode="before")

View File

@ -36,7 +36,7 @@
<body class="mat-app-background" oncontextmenu="return false;"> <body class="mat-app-background" oncontextmenu="return false;">
<app-root></app-root> <app-root></app-root>
<!-- Global site tag (gtag.js) - Google Analytics --> <!-- Global site tag (gtag.js) - Google Analytics -->
<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-5D6FZL9923"></script> <script async="" src="https://www.googletagmanager.com/gtag/js?id=G-0BT7QQV1W1"></script>
<script> <script>
window.dataLayer = window.dataLayer || []; window.dataLayer = window.dataLayer || [];
function gtag() { function gtag() {
@ -44,8 +44,8 @@
} }
gtag('js', new Date()); gtag('js', new Date());
gtag('config', 'G-5D6FZL9923'); gtag('config', 'G-0BT7QQV1W1');
</script> </script>
<script src="runtime.24fa95b7061d7056.js" type="module"></script><script src="polyfills.319c79dd175e50d0.js" type="module"></script><script src="main.f3840f9b1c0240e6.js" type="module"></script> <script src="runtime.24fa95b7061d7056.js" type="module"></script><script src="polyfills.319c79dd175e50d0.js" type="module"></script><script src="main.4185a8e61824af0d.js" type="module"></script>
</body></html> </body></html>

View File

@ -21,6 +21,8 @@ import re
import shlex import shlex
import textwrap import textwrap
import posixpath import posixpath
import socket
import errno
def force_unix_path(path): def force_unix_path(path):
@ -89,3 +91,21 @@ def parse_version(version):
version.append("000000") version.append("000000")
version.append("final") version.append("final")
return tuple(version) return tuple(version)
def is_ipv6_enabled() -> bool:
if not socket.has_ipv6:
return False # the socket library has no support for IPv6
try:
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as sock:
sock.bind(("::1", 0))
return True
except OSError as e:
if e.errno in (errno.EADDRNOTAVAIL, errno.EAFNOSUPPORT):
# EADDRNOTAVAIL is the errno if IPv6 modules/drivers are loaded but disabled.
# EAFNOSUPPORT is the errno if IPv6 modules/drivers are not loaded at all.
return False
if e.errno == errno.EADDRINUSE:
return True
raise

View File

@ -32,6 +32,28 @@ def is_ios_hostname_valid(hostname: str) -> bool:
return False return False
def to_ios_hostname(name):
"""
Convert name to an IOS hostname
"""
# Replace invalid characters with hyphens
name = re.sub(r'[^a-zA-Z0-9-]', '-', name)
# Ensure the hostname starts with a letter
if not re.search(r'^[a-zA-Z]', name):
name = 'a' + name
# Ensure the hostname ends with a letter or digit
if not re.search(r'[a-zA-Z0-9]$', name):
name = name.rstrip('-') + '0'
# Truncate the hostname to 63 characters
name = name[:63]
return name
def is_rfc1123_hostname_valid(hostname: str) -> bool: def is_rfc1123_hostname_valid(hostname: str) -> bool:
""" """
Check if a hostname is valid according to RFC 1123 Check if a hostname is valid according to RFC 1123
@ -57,3 +79,34 @@ def is_rfc1123_hostname_valid(hostname: str) -> bool:
allowed = re.compile(r"(?!-)[a-zA-Z0-9-]{1,63}(?<!-)$") allowed = re.compile(r"(?!-)[a-zA-Z0-9-]{1,63}(?<!-)$")
return all(allowed.match(label) for label in labels) return all(allowed.match(label) for label in labels)
def to_rfc1123_hostname(name: str) -> str:
"""
Convert name to RFC 1123 hostname
"""
# Replace invalid characters with hyphens
name = re.sub(r'[^a-zA-Z0-9-.]', '-', name)
# Remove trailing dot if it exists
name = name.rstrip('.')
# Ensure each label is not longer than 63 characters
labels = name.split('.')
labels = [label[:63] for label in labels]
# Remove leading and trailing hyphens from each label if they exist
labels = [label.strip('-') for label in labels]
# Check if the TLD is all-numeric and if so, replace it with "invalid"
if re.match(r"[0-9]+$", labels[-1]):
labels[-1] = 'invalid'
# Join the labels back together
name = '.'.join(labels)
# Ensure the total length is not longer than 253 characters
name = name[:253]
return name

View File

@ -22,7 +22,7 @@
# 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__ = "3.0.0b3" __version__ = "3.0.0rc1"
__version_info__ = (3, 0, 0, -99) __version_info__ = (3, 0, 0, -99)
if "dev" in __version__: if "dev" in __version__:

View File

@ -1,23 +1,23 @@
uvicorn==0.29.0 uvicorn==0.29.0
fastapi==0.111.0 fastapi==0.112.0
python-multipart==0.0.9 python-multipart==0.0.9
websockets==12.0 websockets==12.0
aiohttp==3.9.3 aiohttp>=3.9.5,<3.10
async-timeout==4.0.3 async-timeout==4.0.3
aiofiles==23.2.1 aiofiles>=24.1.0,<25.0
Jinja2>=3.1.4,<3.2 Jinja2>=3.1.4,<3.2
sentry-sdk==2.1.1,<2.2 sentry-sdk==2.12,<2.13
psutil==5.9.8 psutil==6.0.0
distro>=1.9.0 distro>=1.9.0
py-cpuinfo==9.0.0 py-cpuinfo==9.0.0
sqlalchemy==2.0.29 sqlalchemy==2.0.31
aiosqlite==0.20.0 aiosqlite==0.20.0
alembic==1.12.1 alembic==1.12.1
bcrypt==4.1.2 bcrypt==4.2.0
python-jose[cryptography]==3.3.0 python-jose[cryptography]==3.3.0
email-validator==2.1.1 email-validator==2.2.0
watchfiles==0.21.0 watchfiles==0.22.0
zstandard==0.22.0 zstandard==0.23.0
platformdirs==4.2.1 platformdirs==4.2.2
importlib-resources>=1.3; python_version <= '3.9' importlib-resources>=1.3; python_version <= '3.9'
truststore>=0.9.1; python_version >= '3.10' truststore>=0.9.1; python_version >= '3.10'

View File

@ -197,8 +197,18 @@ then
# Force hostid for IOU # Force hostid for IOU
dd if=/dev/zero bs=4 count=1 of=/etc/hostid dd if=/dev/zero bs=4 count=1 of=/etc/hostid
# Block iou call. The server is down # Block potential IOU phone home call (xml.cisco.com is not in use at this time)
log "Block IOU phone home call"
if [ "$UBUNTU_CODENAME" == "focal" ]
then
iptables -I OUTPUT -p udp --dport 53 -m string --hex-string "|03|xml|05|cisco|03|com" --algo bm -j DROP
echo iptables-persistent iptables-persistent/autosave_v4 boolean true | debconf-set-selections
echo iptables-persistent iptables-persistent/autosave_v6 boolean true | debconf-set-selections
apt-get install -y iptables-persistent
else
echo "127.0.0.254 xml.cisco.com" | tee --append /etc/hosts echo "127.0.0.254 xml.cisco.com" | tee --append /etc/hosts
fi
fi fi
log "Add gns3 to the kvm group" log "Add gns3 to the kvm group"

View File

@ -792,6 +792,14 @@ async def test_build_command_with_invalid_options(vm):
await vm._build_command() await vm._build_command()
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
async def test_build_command_with_forbidden_options(vm):
vm.options = "-blockdev"
with pytest.raises(QemuError):
await vm._build_command()
def test_hda_disk_image(vm, images_dir): def test_hda_disk_image(vm, images_dir):
open(os.path.join(images_dir, "test1"), "w+").close() open(os.path.join(images_dir, "test1"), "w+").close()

View File

@ -334,7 +334,7 @@ async def test_export_with_images(tmpdir, project):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_export_keep_compute_id(tmpdir, project): async def test_export_keep_compute_ids(tmpdir, project):
""" """
If we want to restore the same computes we could ask to keep them If we want to restore the same computes we could ask to keep them
in the file in the file
@ -363,7 +363,7 @@ async def test_export_keep_compute_id(tmpdir, project):
json.dump(data, f) json.dump(data, f)
with aiozipstream.ZipFile() as z: with aiozipstream.ZipFile() as z:
await export_project(z, project, str(tmpdir), keep_compute_id=True) await export_project(z, project, str(tmpdir), keep_compute_ids=True)
await write_file(str(tmpdir / 'zipfile.zip'), z) await write_file(str(tmpdir / 'zipfile.zip'), z)
with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip: with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip:
@ -469,7 +469,7 @@ async def test_export_with_ignoring_snapshots(tmpdir, project):
Path(os.path.join(snapshots_dir, 'snap.gns3project')).touch() Path(os.path.join(snapshots_dir, 'snap.gns3project')).touch()
with aiozipstream.ZipFile() as z: with aiozipstream.ZipFile() as z:
await export_project(z, project, str(tmpdir), keep_compute_id=True) await export_project(z, project, str(tmpdir), keep_compute_ids=True)
await write_file(str(tmpdir / 'zipfile.zip'), z) await write_file(str(tmpdir / 'zipfile.zip'), z)
with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip: with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip:

View File

@ -462,7 +462,7 @@ async def test_import_node_id(linux_platform, tmpdir, controller):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_import_keep_compute_id(windows_platform, tmpdir, controller): async def test_import_keep_compute_ids(windows_platform, tmpdir, controller):
""" """
On linux host IOU should be moved to the GNS3 VM On linux host IOU should be moved to the GNS3 VM
""" """
@ -500,7 +500,7 @@ async def test_import_keep_compute_id(windows_platform, tmpdir, controller):
myzip.write(str(tmpdir / "project.gns3"), "project.gns3") myzip.write(str(tmpdir / "project.gns3"), "project.gns3")
with open(zip_path, "rb") as f: with open(zip_path, "rb") as f:
project = await import_project(controller, project_id, f, keep_compute_id=True) project = await import_project(controller, project_id, f, keep_compute_ids=True)
with open(os.path.join(project.path, "test.gns3")) as f: with open(os.path.join(project.path, "test.gns3")) as f:
topo = json.load(f) topo = json.load(f)

View File

@ -786,7 +786,7 @@ def test_snapshots(project):
def test_get_snapshot(project): def test_get_snapshot(project):
os.makedirs(os.path.join(project.path, "snapshots")) os.makedirs(os.path.join(project.path, "snapshots"))
open(os.path.join(project.path, "snapshots", "test1.gns3project"), "w+").close() open(os.path.join(project.path, "snapshots", "test1_260716_103713.gns3project"), "w+").close()
project.reset() project.reset()
snapshot = list(project.snapshots.values())[0] snapshot = list(project.snapshots.values())[0]

View File

@ -61,15 +61,21 @@ def test_snapshot_filename(project):
def test_json(project): def test_json(project):
snapshot = Snapshot(project, filename="test1_260716_100439.gns3project") snapshot = Snapshot(project, filename="snapshot_test_260716_100439.gns3project")
assert snapshot.asdict() == { assert snapshot.asdict() == {
"snapshot_id": snapshot._id, "snapshot_id": snapshot._id,
"name": "test1", "name": "snapshot_test",
"project_id": project.id, "project_id": project.id,
"created_at": 1469527479 "created_at": 1469527479
} }
def test_invalid_snapshot_filename(project):
with pytest.raises(ValueError):
Snapshot(project, filename="snapshot_test_invalid_file.gns3project")
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_restore(project, controller, config): async def test_restore(project, controller, config):

View File

@ -23,11 +23,11 @@
"label": { "label": {
"rotation": 0, "rotation": 0,
"style": "font-family: TypeWriter;font-size: 10;font-weight: bold;fill: #000000;fill-opacity: 1.0;", "style": "font-family: TypeWriter;font-size: 10;font-weight: bold;fill: #000000;fill-opacity: 1.0;",
"text": "remote_busybox-1", "text": "remote-busybox-1",
"x": -20, "x": -20,
"y": -25 "y": -25
}, },
"name": "remote_busybox-1", "name": "remote-busybox-1",
"node_id": "d397ef5a-84f1-4b6b-9d44-671937ec7781", "node_id": "d397ef5a-84f1-4b6b-9d44-671937ec7781",
"node_type": "docker", "node_type": "docker",
"port_name_format": "Ethernet{0}", "port_name_format": "Ethernet{0}",

View File

@ -11,7 +11,7 @@
"label": { "label": {
"color": "#ff000000", "color": "#ff000000",
"font": "TypeWriter,10,-1,5,75,0,0,0,0,0", "font": "TypeWriter,10,-1,5,75,0,0,0,0,0",
"text": "remote_busybox-1", "text": "remote-busybox-1",
"x": -20.4453125, "x": -20.4453125,
"y": -25.0 "y": -25.0
}, },
@ -32,7 +32,7 @@
"console_resolution": "1024x768", "console_resolution": "1024x768",
"console_type": "telnet", "console_type": "telnet",
"image": "busybox:latest", "image": "busybox:latest",
"name": "remote_busybox-1" "name": "remote-busybox-1"
}, },
"server_id": 2, "server_id": 2,
"type": "DockerVM", "type": "DockerVM",

View File

@ -0,0 +1,222 @@
{
"auto_close": true,
"auto_open": false,
"auto_start": false,
"drawing_grid_size": 25,
"grid_size": 75,
"name": "test-hostnames",
"project_id": "8b83e3ac-6b6a-4d6b-9938-bd630a6e458e",
"revision": 10,
"scene_height": 1000,
"scene_width": 2000,
"show_grid": false,
"show_interface_labels": false,
"show_layers": false,
"snap_to_grid": false,
"supplier": null,
"topology": {
"computes": [],
"drawings": [],
"links": [],
"nodes": [
{
"compute_id": "local",
"console": 5000,
"console_auto_start": false,
"console_type": "telnet",
"custom_adapters": [],
"first_port_name": null,
"height": 45,
"label": {
"rotation": 0,
"style": "font-family: TypeWriter;font-size: 10.0;font-weight: bold;fill: #000000;fill-opacity: 1.0;",
"text": "42Router_A-1",
"x": -20,
"y": -25
},
"locked": false,
"name": "a42Router-A-1",
"node_id": "adb89fbb-92ba-419b-96ca-1ad0f03ce3f6",
"node_type": "dynamips",
"port_name_format": "Ethernet{0}",
"port_segment_size": 0,
"properties": {
"auto_delete_disks": false,
"aux": null,
"clock_divisor": 8,
"disk0": 0,
"disk1": 0,
"dynamips_id": 1,
"exec_area": 64,
"idlemax": 500,
"idlepc": "0x60aa1da0",
"idlesleep": 30,
"image": "c3745-adventerprisek9-mz.124-25d.image",
"image_md5sum": "ddbaf74274822b50fa9670e10c75b08f",
"iomem": 5,
"mac_addr": "c401.fff5.0000",
"mmap": true,
"nvram": 256,
"platform": "c3745",
"ram": 256,
"slot0": "GT96100-FE",
"slot1": "NM-1FE-TX",
"slot2": "NM-4T",
"slot3": null,
"slot4": null,
"sparsemem": true,
"system_id": "FTX0945W0MY",
"usage": "",
"wic0": "WIC-1T",
"wic1": "WIC-1T",
"wic2": "WIC-1T"
},
"symbol": ":/symbols/classic/router.svg",
"template_id": "24f09d1a-64e1-4dc4-ae49-e785c1dbc0c5",
"width": 66,
"x": -130,
"y": -64,
"z": 1
},
{
"compute_id": "local",
"console": 5001,
"console_auto_start": false,
"console_type": "telnet",
"custom_adapters": [
{
"adapter_number": 0,
"adapter_type": "e1000"
},
{
"adapter_number": 1,
"adapter_type": "e1000"
},
{
"adapter_number": 2,
"adapter_type": "e1000"
},
{
"adapter_number": 3,
"adapter_type": "e1000"
},
{
"adapter_number": 4,
"adapter_type": "e1000"
},
{
"adapter_number": 5,
"adapter_type": "e1000"
},
{
"adapter_number": 6,
"adapter_type": "e1000"
},
{
"adapter_number": 7,
"adapter_type": "e1000"
},
{
"adapter_number": 8,
"adapter_type": "e1000"
},
{
"adapter_number": 9,
"adapter_type": "e1000"
},
{
"adapter_number": 10,
"adapter_type": "e1000"
},
{
"adapter_number": 11,
"adapter_type": "e1000"
},
{
"adapter_number": 12,
"adapter_type": "e1000"
},
{
"adapter_number": 13,
"adapter_type": "e1000"
},
{
"adapter_number": 14,
"adapter_type": "e1000"
},
{
"adapter_number": 15,
"adapter_type": "e1000"
}
],
"first_port_name": "",
"height": 48,
"label": {
"rotation": 0,
"style": "font-family: TypeWriter;font-size: 10.0;font-weight: bold;fill: #000000;fill-opacity: 1.0;",
"text": "Switch_10.0.0.1",
"x": -36,
"y": -25
},
"locked": false,
"name": "Switch-10.0.0.invalid",
"node_id": "ccda4e49-770f-4237-956b-cc7281630468",
"node_type": "qemu",
"port_name_format": "Gi0/{0}",
"port_segment_size": 4,
"properties": {
"adapter_type": "e1000",
"adapters": 16,
"bios_image": "",
"bios_image_md5sum": null,
"boot_priority": "c",
"cdrom_image": "",
"cdrom_image_md5sum": null,
"cpu_throttling": 0,
"cpus": 1,
"create_config_disk": false,
"hda_disk_image": "vios_l2-adventerprisek9-m.03.2017.qcow2",
"hda_disk_image_md5sum": "8f14b50083a14688dec2fc791706bb3e",
"hda_disk_interface": "virtio",
"hdb_disk_image": "",
"hdb_disk_image_md5sum": null,
"hdb_disk_interface": "none",
"hdc_disk_image": "",
"hdc_disk_image_md5sum": null,
"hdc_disk_interface": "none",
"hdd_disk_image": "",
"hdd_disk_image_md5sum": null,
"hdd_disk_interface": "none",
"initrd": "",
"initrd_md5sum": null,
"kernel_command_line": "",
"kernel_image": "",
"kernel_image_md5sum": null,
"legacy_networking": false,
"linked_clone": true,
"mac_address": "0c:da:4e:49:00:00",
"on_close": "power_off",
"options": "",
"platform": "x86_64",
"process_priority": "normal",
"qemu_path": "/bin/qemu-system-x86_64",
"ram": 768,
"replicate_network_connection_state": true,
"tpm": false,
"uefi": false,
"usage": "There is no default password and enable password. There is no default configuration present. SUPER UPDATED!"
},
"symbol": ":/symbols/classic/multilayer_switch.svg",
"template_id": "9db64790-65f4-4d38-a1ac-2f6ce45b70db",
"width": 51,
"x": -13,
"y": 54,
"z": 1
}
]
},
"type": "topology",
"variables": null,
"version": "2.2.49",
"zoom": 100
}

View File

@ -0,0 +1,222 @@
{
"auto_close": true,
"auto_open": false,
"auto_start": false,
"drawing_grid_size": 25,
"grid_size": 75,
"name": "test-hostnames",
"project_id": "8b83e3ac-6b6a-4d6b-9938-bd630a6e458e",
"revision": 9,
"scene_height": 1000,
"scene_width": 2000,
"show_grid": false,
"show_interface_labels": false,
"show_layers": false,
"snap_to_grid": false,
"supplier": null,
"topology": {
"computes": [],
"drawings": [],
"links": [],
"nodes": [
{
"compute_id": "local",
"console": 5000,
"console_auto_start": false,
"console_type": "telnet",
"custom_adapters": [],
"first_port_name": null,
"height": 45,
"label": {
"rotation": 0,
"style": "font-family: TypeWriter;font-size: 10.0;font-weight: bold;fill: #000000;fill-opacity: 1.0;",
"text": "42Router_A-1",
"x": -20,
"y": -25
},
"locked": false,
"name": "42Router_A-1",
"node_id": "adb89fbb-92ba-419b-96ca-1ad0f03ce3f6",
"node_type": "dynamips",
"port_name_format": "Ethernet{0}",
"port_segment_size": 0,
"properties": {
"auto_delete_disks": false,
"aux": null,
"clock_divisor": 8,
"disk0": 0,
"disk1": 0,
"dynamips_id": 1,
"exec_area": 64,
"idlemax": 500,
"idlepc": "0x60aa1da0",
"idlesleep": 30,
"image": "c3745-adventerprisek9-mz.124-25d.image",
"image_md5sum": "ddbaf74274822b50fa9670e10c75b08f",
"iomem": 5,
"mac_addr": "c401.fff5.0000",
"mmap": true,
"nvram": 256,
"platform": "c3745",
"ram": 256,
"slot0": "GT96100-FE",
"slot1": "NM-1FE-TX",
"slot2": "NM-4T",
"slot3": null,
"slot4": null,
"sparsemem": true,
"system_id": "FTX0945W0MY",
"usage": "",
"wic0": "WIC-1T",
"wic1": "WIC-1T",
"wic2": "WIC-1T"
},
"symbol": ":/symbols/classic/router.svg",
"template_id": "24f09d1a-64e1-4dc4-ae49-e785c1dbc0c5",
"width": 66,
"x": -130,
"y": -64,
"z": 1
},
{
"compute_id": "local",
"console": 5001,
"console_auto_start": false,
"console_type": "telnet",
"custom_adapters": [
{
"adapter_number": 0,
"adapter_type": "e1000"
},
{
"adapter_number": 1,
"adapter_type": "e1000"
},
{
"adapter_number": 2,
"adapter_type": "e1000"
},
{
"adapter_number": 3,
"adapter_type": "e1000"
},
{
"adapter_number": 4,
"adapter_type": "e1000"
},
{
"adapter_number": 5,
"adapter_type": "e1000"
},
{
"adapter_number": 6,
"adapter_type": "e1000"
},
{
"adapter_number": 7,
"adapter_type": "e1000"
},
{
"adapter_number": 8,
"adapter_type": "e1000"
},
{
"adapter_number": 9,
"adapter_type": "e1000"
},
{
"adapter_number": 10,
"adapter_type": "e1000"
},
{
"adapter_number": 11,
"adapter_type": "e1000"
},
{
"adapter_number": 12,
"adapter_type": "e1000"
},
{
"adapter_number": 13,
"adapter_type": "e1000"
},
{
"adapter_number": 14,
"adapter_type": "e1000"
},
{
"adapter_number": 15,
"adapter_type": "e1000"
}
],
"first_port_name": "",
"height": 48,
"label": {
"rotation": 0,
"style": "font-family: TypeWriter;font-size: 10.0;font-weight: bold;fill: #000000;fill-opacity: 1.0;",
"text": "Switch_10.0.0.1",
"x": -36,
"y": -25
},
"locked": false,
"name": "Switch_10.0.0.1",
"node_id": "ccda4e49-770f-4237-956b-cc7281630468",
"node_type": "qemu",
"port_name_format": "Gi0/{0}",
"port_segment_size": 4,
"properties": {
"adapter_type": "e1000",
"adapters": 16,
"bios_image": "",
"bios_image_md5sum": null,
"boot_priority": "c",
"cdrom_image": "",
"cdrom_image_md5sum": null,
"cpu_throttling": 0,
"cpus": 1,
"create_config_disk": false,
"hda_disk_image": "vios_l2-adventerprisek9-m.03.2017.qcow2",
"hda_disk_image_md5sum": "8f14b50083a14688dec2fc791706bb3e",
"hda_disk_interface": "virtio",
"hdb_disk_image": "",
"hdb_disk_image_md5sum": null,
"hdb_disk_interface": "none",
"hdc_disk_image": "",
"hdc_disk_image_md5sum": null,
"hdc_disk_interface": "none",
"hdd_disk_image": "",
"hdd_disk_image_md5sum": null,
"hdd_disk_interface": "none",
"initrd": "",
"initrd_md5sum": null,
"kernel_command_line": "",
"kernel_image": "",
"kernel_image_md5sum": null,
"legacy_networking": false,
"linked_clone": true,
"mac_address": "0c:da:4e:49:00:00",
"on_close": "power_off",
"options": "",
"platform": "x86_64",
"process_priority": "normal",
"qemu_path": "/bin/qemu-system-x86_64",
"ram": 768,
"replicate_network_connection_state": true,
"tpm": false,
"uefi": false,
"usage": "There is no default password and enable password. There is no default configuration present. SUPER UPDATED!"
},
"symbol": ":/symbols/classic/multilayer_switch.svg",
"template_id": "9db64790-65f4-4d38-a1ac-2f6ce45b70db",
"width": 51,
"x": -13,
"y": 54,
"z": 1
}
]
},
"type": "topology",
"variables": null,
"version": "2.2.49",
"zoom": 100
}

View File

@ -0,0 +1,121 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2024 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from gns3server.utils import hostname
def test_ios_hostname_valid_with_valid_hostnames():
assert hostname.is_ios_hostname_valid("router1")
assert hostname.is_ios_hostname_valid("switch-2")
assert hostname.is_ios_hostname_valid("a1-b2-c3")
def test_ios_hostname_valid_with_invalid_hostnames():
assert not hostname.is_ios_hostname_valid("-router")
assert not hostname.is_ios_hostname_valid("router-")
assert not hostname.is_ios_hostname_valid("123router")
assert not hostname.is_ios_hostname_valid("router@123")
assert not hostname.is_ios_hostname_valid("router.router")
def test_ios_hostname_valid_with_long_hostnames():
assert hostname.is_ios_hostname_valid("a" * 63)
assert not hostname.is_ios_hostname_valid("a" * 64)
def test_ios_hostname_conversion_with_valid_characters():
assert hostname.to_ios_hostname("validHostname123") == "validHostname123"
def test_ios_hostname_conversion_starts_with_digit():
assert hostname.to_ios_hostname("1InvalidStart") == "a1InvalidStart"
def test_ios_hostname_conversion_starts_with_special_character():
assert hostname.to_ios_hostname("@InvalidStart") == "a-InvalidStart"
def test_ios_hostname_conversion_ends_with_special_character():
assert hostname.to_ios_hostname("InvalidEnd-") == "InvalidEnd0"
def test_ios_hostname_conversion_contains_special_characters():
assert hostname.to_ios_hostname("Invalid@Hostname!") == "Invalid-Hostname0"
def test_ios_hostname_conversion_exceeds_max_length():
long_name = "a" * 64
assert hostname.to_ios_hostname(long_name) == "a" * 63
def test_ios_hostname_conversion_just_right_length():
exact_length_name = "a" * 63
assert hostname.to_ios_hostname(exact_length_name) == "a" * 63
def test_rfc1123_hostname_validity_with_valid_hostnames():
assert hostname.is_rfc1123_hostname_valid("example.com")
assert hostname.is_rfc1123_hostname_valid("subdomain.example.com")
assert hostname.is_rfc1123_hostname_valid("example-hyphen.com")
assert hostname.is_rfc1123_hostname_valid("example.com.")
assert hostname.is_rfc1123_hostname_valid("123.com")
def test_rfc1123_hostname_validity_with_invalid_hostnames():
assert not hostname.is_rfc1123_hostname_valid("-example.com")
assert not hostname.is_rfc1123_hostname_valid("example-.com")
assert not hostname.is_rfc1123_hostname_valid("example..com")
assert not hostname.is_rfc1123_hostname_valid("example_com")
assert not hostname.is_rfc1123_hostname_valid("example.123")
def test_rfc1123_hostname_validity_with_long_hostnames():
long_hostname = "a" * 63 + "." + "b" * 63 + "." + "c" * 63 + "." + "d" * 61 # 253 characters
too_long_hostname = long_hostname + "e"
assert hostname.is_rfc1123_hostname_valid(long_hostname)
assert not hostname.is_rfc1123_hostname_valid(too_long_hostname)
def test_rfc1123_conversion_hostname_with_valid_characters():
assert hostname.to_rfc1123_hostname("valid-hostname.example.com") == "valid-hostname.example.com"
def test_rfc1123_conversion_hostname_with_invalid_characters_replaced():
assert hostname.to_rfc1123_hostname("invalid_hostname!@#$.example") == "invalid-hostname.example"
def test_rfc1123_conversion_hostname_with_trailing_dot_removed():
assert hostname.to_rfc1123_hostname("hostname.example.com.") == "hostname.example.com"
def test_rfc1123_conversion_hostname_with_labels_exceeding_63_characters():
long_label = "a" * 64 + ".example.com"
expected_label = "a" * 63 + ".example.com"
assert hostname.to_rfc1123_hostname(long_label) == expected_label
def test_rfc1123_conversion_hostname_with_total_length_exceeding_253_characters():
long_hostname = "a" * 50 + "." + "b" * 50 + "." + "c" * 50 + "." + "d" * 50 + "." + "e" * 50
assert len(hostname.to_rfc1123_hostname(long_hostname)) <= 253
def test_rfc1123_conversion_hostname_with_all_numeric_tld_replaced():
assert hostname.to_rfc1123_hostname("hostname.123") == "hostname.invalid"
def rfc1123_hostname_with_multiple_consecutive_invalid_characters():
assert hostname.to_rfc1123_hostname("hostname!!!.example..com") == "hostname---.example.com"