diff --git a/.github/workflows/add-new-issues-to-project.yml b/.github/workflows/add-new-issues-to-project.yml index 63932bb4..aa825255 100644 --- a/.github/workflows/add-new-issues-to-project.yml +++ b/.github/workflows/add-new-issues-to-project.yml @@ -10,7 +10,7 @@ jobs: name: Add issue to project runs-on: ubuntu-latest steps: - - uses: actions/add-to-project@v0.4.0 + - uses: actions/add-to-project@v1.0.1 with: project-url: https://github.com/orgs/GNS3/projects/3 github-token: ${{ secrets.ADD_NEW_ISSUES_TO_PROJECT }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 54e2f8e1..06ab2cc6 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,58 +13,81 @@ name: "CodeQL" on: push: - branches: [ master ] + branches: [ "master" ] pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] + branches: [ "master" ] schedule: - - cron: '44 1 * * 3' + - cron: '21 12 * * 4' jobs: analyze: - name: Analyze - runs-on: ubuntu-latest + name: Analyze (${{ matrix.language }}) + # 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: + # 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 contents: read - security-events: write strategy: fail-fast: false matrix: - language: [ 'python' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://git.io/codeql-language-support - + include: + - language: python + 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: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v3 with: 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. # 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. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 + # 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 + # queries: security-extended,security-and-quality + # 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. - # đ https://git.io/JvXDl - - # âī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release + # đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + 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' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/publish-api-documentation.yml b/.github/workflows/publish-api-documentation.yml index 68bd91cd..4df3f308 100644 --- a/.github/workflows/publish-api-documentation.yml +++ b/.github/workflows/publish-api-documentation.yml @@ -12,11 +12,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 ref: "gh-pages" - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v5 with: python-version: 3.8 - name: Merge changes from 3.0 branch diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 01c4fdda..4713c6da 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -20,9 +20,9 @@ jobs: python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Display Python version diff --git a/CHANGELOG b/CHANGELOG index a95a4410..c39cc7ba 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,32 @@ # 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 * Bundle web-ui v3.0.0b3 diff --git a/dev-requirements.txt b/dev-requirements.txt index e7f280d3..0fa15092 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,7 +1,7 @@ -pytest==8.1.1 -flake8==7.0.0 +pytest==8.3.2 +flake8==7.1.0 pytest-timeout==2.3.1 -pytest-asyncio==0.21.1 -requests==2.31.0 +pytest-asyncio==0.21.2 +requests==2.32.3 httpx==0.24.1 # version 0.24.1 is required by httpx_ws httpx_ws==0.4.2 diff --git a/gns3server/api/routes/controller/projects.py b/gns3server/api/routes/controller/projects.py index 433832a8..fa088534 100644 --- a/gns3server/api/routes/controller/projects.py +++ b/gns3server/api/routes/controller/projects.py @@ -320,6 +320,7 @@ async def export_project( include_snapshots: bool = False, include_images: bool = False, reset_mac_addresses: bool = False, + keep_compute_ids: bool = False, compression: schemas.ProjectCompression = "zstd", compression_level: int = None, ) -> StreamingResponse: @@ -366,6 +367,7 @@ async def export_project( tmpdir, include_snapshots=include_snapshots, include_images=include_images, + keep_compute_ids=keep_compute_ids, reset_mac_addresses=reset_mac_addresses, ) async for chunk in zstream: diff --git a/gns3server/appliances/aruba-arubaoscx.gns3a b/gns3server/appliances/aruba-arubaoscx.gns3a index 1fecc275..893f66ec 100644 --- a/gns3server/appliances/aruba-arubaoscx.gns3a +++ b/gns3server/appliances/aruba-arubaoscx.gns3a @@ -32,6 +32,27 @@ "process_priority": "normal" }, "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", "version": "10.12.0006", @@ -118,6 +139,24 @@ } ], "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", "images": { diff --git a/gns3server/appliances/cisco-iou-l2.gns3a b/gns3server/appliances/cisco-iou-l2.gns3a index ba8dfdf8..546cc36c 100644 --- a/gns3server/appliances/cisco-iou-l2.gns3a +++ b/gns3server/appliances/cisco-iou-l2.gns3a @@ -19,7 +19,7 @@ }, "images": [ { - "filename": "x86_64_crb_linux_l2-adventerprisek9-ms", + "filename": "x86_64_crb_linux_l2-adventerprisek9-ms.bin", "version": "17.12.1", "md5sum": "2b5055e4cef8fd257416d74a94adb626", "filesize": 240355720 @@ -47,7 +47,7 @@ { "name": "17.12.1", "images": { - "image": "x86_64_crb_linux_l2-adventerprisek9-ms" + "image": "x86_64_crb_linux_l2-adventerprisek9-ms.bin" } }, { diff --git a/gns3server/appliances/cisco-iou-l3.gns3a b/gns3server/appliances/cisco-iou-l3.gns3a index 083a6eb9..f7328449 100644 --- a/gns3server/appliances/cisco-iou-l3.gns3a +++ b/gns3server/appliances/cisco-iou-l3.gns3a @@ -19,7 +19,7 @@ }, "images": [ { - "filename": "x86_64_crb_linux-adventerprisek9-ms", + "filename": "x86_64_crb_linux-adventerprisek9-ms.bin", "version": "17.12.1", "md5sum": "4a2fce8de21d1831fbceffd155e41ae7", "filesize": 288947184 @@ -47,7 +47,7 @@ { "name": "17.12.1", "images": { - "image": "x86_64_crb_linux-adventerprisek9-ms" + "image": "x86_64_crb_linux-adventerprisek9-ms.bin" } }, { diff --git a/gns3server/appliances/debian.gns3a b/gns3server/appliances/debian.gns3a index 0d1defd8..47dfe599 100644 --- a/gns3server/appliances/debian.gns3a +++ b/gns3server/appliances/debian.gns3a @@ -23,6 +23,14 @@ "kvm": "allow" }, "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", "version": "12.4", @@ -31,6 +39,14 @@ "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" }, + { + "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", "version": "11.8", @@ -41,12 +57,24 @@ } ], "versions": [ + { + "name": "12.6", + "images": { + "hda_disk_image": "debian-12.6.qcow2" + } + }, { "name": "12.4", "images": { "hda_disk_image": "debian-12.4.qcow2" } }, + { + "name": "11.10", + "images": { + "hda_disk_image": "debian-11.10.qcow2" + } + }, { "name": "11.8", "images": { diff --git a/gns3server/appliances/fortiadc.gns3a b/gns3server/appliances/fortiadc.gns3a index 5996848c..16cca8f2 100644 --- a/gns3server/appliances/fortiadc.gns3a +++ b/gns3server/appliances/fortiadc.gns3a @@ -28,10 +28,17 @@ }, "images": [ { - "filename": "FAD_KVM-FORTINET.out.kvm-data.qcow2", - "version": "ALL", - "md5sum": "b7500835594e62d8acb1c6ec43d597c1", - "filesize": 30998528, + "filename": "FAD_KVM-V7.4.4-build0347-FORTINET.out.kvm_boot.qcow2", + "version": "7.4.4", + "md5sum": "52fa343fd423a1a560473b8cf02f4c9c", + "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" }, { @@ -41,6 +48,13 @@ "filesize": 145817600, "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", "version": "7.1.1", @@ -243,9 +257,30 @@ "md5sum": "7a71f52bde93c0000b047626731b7aef", "filesize": 68026368, "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": [ + { + "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", "images": { @@ -253,6 +288,13 @@ "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", "images": { diff --git a/gns3server/appliances/fortianalyzer.gns3a b/gns3server/appliances/fortianalyzer.gns3a index db14866d..9bbed071 100644 --- a/gns3server/appliances/fortianalyzer.gns3a +++ b/gns3server/appliances/fortianalyzer.gns3a @@ -29,6 +29,13 @@ "kvm": "allow" }, "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", "version": "7.4.2", @@ -43,6 +50,13 @@ "filesize": 435310592, "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", "version": "7.2.4", @@ -64,6 +78,13 @@ "filesize": 340631552, "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", "version": "7.0.11", @@ -256,6 +277,13 @@ } ], "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", "images": { @@ -270,6 +298,13 @@ "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", "images": { @@ -291,6 +326,13 @@ "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", "images": { diff --git a/gns3server/appliances/fortiauthenticator.gns3a b/gns3server/appliances/fortiauthenticator.gns3a index 6ce0bb96..d6a0b36a 100644 --- a/gns3server/appliances/fortiauthenticator.gns3a +++ b/gns3server/appliances/fortiauthenticator.gns3a @@ -13,13 +13,13 @@ "status": "stable", "maintainer": "GNS3 Team", "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", "port_name_format": "Port{port1}", "qemu": { "adapter_type": "e1000", "adapters": 4, - "ram": 1024, + "ram": 4096, "hda_disk_interface": "virtio", "hdb_disk_interface": "virtio", "arch": "x86_64", @@ -28,6 +28,27 @@ "kvm": "allow" }, "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", "version": "6.0.3", @@ -105,6 +126,20 @@ "filesize": 62771200, "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", "version": "All", @@ -114,6 +149,27 @@ } ], "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", "images": { diff --git a/gns3server/appliances/fortigate.gns3a b/gns3server/appliances/fortigate.gns3a index 77f2c7d7..4fb16e0c 100644 --- a/gns3server/appliances/fortigate.gns3a +++ b/gns3server/appliances/fortigate.gns3a @@ -28,6 +28,13 @@ "kvm": "allow" }, "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", "version": "7.4.3", @@ -42,6 +49,13 @@ "filesize": 116064256, "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", "version": "7.2.7", @@ -77,6 +91,13 @@ "filesize": 86704128, "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", "version": "7.0.14", @@ -367,6 +388,13 @@ } ], "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", "images": { @@ -381,6 +409,13 @@ "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", "images": { @@ -416,6 +451,13 @@ "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", "images": { diff --git a/gns3server/appliances/fortimanager.gns3a b/gns3server/appliances/fortimanager.gns3a index 28c53e0b..15b13a20 100644 --- a/gns3server/appliances/fortimanager.gns3a +++ b/gns3server/appliances/fortimanager.gns3a @@ -29,6 +29,13 @@ "kvm": "allow" }, "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", "version": "7.4.2", @@ -43,6 +50,13 @@ "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", @@ -64,6 +78,13 @@ "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", @@ -256,6 +277,13 @@ } ], "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", "images": { @@ -270,6 +298,13 @@ "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": { @@ -291,6 +326,13 @@ "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": { diff --git a/gns3server/appliances/fortiweb.gns3a b/gns3server/appliances/fortiweb.gns3a index 1c322a6b..bd46e2d4 100644 --- a/gns3server/appliances/fortiweb.gns3a +++ b/gns3server/appliances/fortiweb.gns3a @@ -28,6 +28,27 @@ "kvm": "allow" }, "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", "version": "7.2.1", @@ -35,6 +56,13 @@ "filesize": 260506112, "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", "version": "7.0.6", @@ -150,6 +178,27 @@ } ], "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", "images": { @@ -157,6 +206,13 @@ "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", "images": { diff --git a/gns3server/appliances/juniper-junos-space.gns3a b/gns3server/appliances/juniper-junos-space.gns3a index c333c349..659d6a5e 100644 --- a/gns3server/appliances/juniper-junos-space.gns3a +++ b/gns3server/appliances/juniper-junos-space.gns3a @@ -12,18 +12,19 @@ "status": "stable", "maintainer": "GNS3 Team", "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", "port_name_format": "em{0}", "qemu": { "adapter_type": "e1000", "adapters": 4, "ram": 16384, + "cpus": 4, "hda_disk_interface": "ide", "arch": "x86_64", "console_type": "telnet", "kvm": "require", - "options": "-smp 4 -nographic" + "options": "-nographic -machine q35,smbios-entry-point-type=32" }, "images": [ { diff --git a/gns3server/appliances/juniper-vmx-legacy.gns3a b/gns3server/appliances/juniper-vmx-legacy.gns3a index 1409c4c7..592c4a60 100644 --- a/gns3server/appliances/juniper-vmx-legacy.gns3a +++ b/gns3server/appliances/juniper-vmx-legacy.gns3a @@ -34,7 +34,7 @@ "arch": "x86_64", "console_type": "telnet", "kvm": "require", - "options": "-nographic" + "options": "-nographic -machine q35,smbios-entry-point-type=32" }, "images": [ { diff --git a/gns3server/appliances/juniper-vmx-vcp.gns3a b/gns3server/appliances/juniper-vmx-vcp.gns3a index 089f4dce..d1d9493c 100644 --- a/gns3server/appliances/juniper-vmx-vcp.gns3a +++ b/gns3server/appliances/juniper-vmx-vcp.gns3a @@ -26,7 +26,7 @@ "arch": "x86_64", "console_type": "telnet", "kvm": "require", - "options": "-nographic -enable-kvm" + "options": "-nographic -enable-kvm -machine q35,smbios-entry-point-type=32" }, "images": [ { diff --git a/gns3server/appliances/juniper-vmx-vfp.gns3a b/gns3server/appliances/juniper-vmx-vfp.gns3a index dba3ee1e..ff1145ef 100644 --- a/gns3server/appliances/juniper-vmx-vfp.gns3a +++ b/gns3server/appliances/juniper-vmx-vfp.gns3a @@ -20,11 +20,12 @@ "adapter_type": "virtio-net-pci", "adapters": 13, "ram": 4096, + "cpus": 4, "hda_disk_interface": "ide", "arch": "x86_64", "console_type": "telnet", "kvm": "require", - "options": "-nographic -enable-kvm -smp cpus=3" + "options": "-nographic -enable-kvm -machine q35,smbios-entry-point-type=32" }, "images": [ { diff --git a/gns3server/appliances/juniper-vqfx-pfe.gns3a b/gns3server/appliances/juniper-vqfx-pfe.gns3a index 23cacef5..7a4c4e21 100644 --- a/gns3server/appliances/juniper-vqfx-pfe.gns3a +++ b/gns3server/appliances/juniper-vqfx-pfe.gns3a @@ -23,7 +23,7 @@ "arch": "x86_64", "console_type": "vnc", "kvm": "require", - "options": "-nographic" + "options": "-nographic -machine q35,smbios-entry-point-type=32" }, "images": [ { diff --git a/gns3server/appliances/juniper-vqfx-re.gns3a b/gns3server/appliances/juniper-vqfx-re.gns3a index b47c34d5..855d2a11 100644 --- a/gns3server/appliances/juniper-vqfx-re.gns3a +++ b/gns3server/appliances/juniper-vqfx-re.gns3a @@ -19,11 +19,12 @@ "adapter_type": "virtio-net-pci", "adapters": 12, "ram": 1024, + "cpus": 2, "hda_disk_interface": "ide", "arch": "x86_64", "console_type": "telnet", "kvm": "require", - "options": "-nographic -smp 2" + "options": "-nographic -machine q35,smbios-entry-point-type=32" }, "images": [ { diff --git a/gns3server/appliances/juniper-vrr.gns3a b/gns3server/appliances/juniper-vrr.gns3a index 8c447a26..8ec4d506 100644 --- a/gns3server/appliances/juniper-vrr.gns3a +++ b/gns3server/appliances/juniper-vrr.gns3a @@ -25,7 +25,7 @@ "arch": "x86_64", "console_type": "telnet", "kvm": "require", - "options": "-nographic -enable-kvm" + "options": "-nographic -enable-kvm -machine q35,smbios-entry-point-type=32" }, "images": [ { diff --git a/gns3server/appliances/juniper-vsrx.gns3a b/gns3server/appliances/juniper-vsrx.gns3a index bd13122d..347632b3 100644 --- a/gns3server/appliances/juniper-vsrx.gns3a +++ b/gns3server/appliances/juniper-vsrx.gns3a @@ -19,11 +19,12 @@ "adapter_type": "vmxnet3", "adapters": 6, "ram": 4096, + "cpus": 2, "hda_disk_interface": "ide", "arch": "x86_64", "console_type": "telnet", "kvm": "require", - "options": "-smp 2" + "options": "-machine q35,smbios-entry-point-type=32" }, "images": [ { diff --git a/gns3server/appliances/pan-vm-fw.gns3a b/gns3server/appliances/pan-vm-fw.gns3a index 1406aed8..5e68ca54 100644 --- a/gns3server/appliances/pan-vm-fw.gns3a +++ b/gns3server/appliances/pan-vm-fw.gns3a @@ -28,6 +28,20 @@ }, "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", "version": "10.1.0", "md5sum": "8266fd412a22694749f2cd4afcd5fa33", @@ -128,6 +142,18 @@ ], "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", "images": { "hda_disk_image": "PA-VM-KVM-10.1.0.qcow2" diff --git a/gns3server/appliances/security-onion.gns3a b/gns3server/appliances/security-onion.gns3a index f4f6cf1a..4841de8f 100644 --- a/gns3server/appliances/security-onion.gns3a +++ b/gns3server/appliances/security-onion.gns3a @@ -13,18 +13,27 @@ "status": "stable", "maintainer": "Brent Stewart", "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", "qemu": { "adapter_type": "e1000", "adapters": 2, - "ram": 3072, + "ram": 4096, "hda_disk_interface": "ide", "arch": "x86_64", "console_type": "vnc", - "kvm": "allow" + "kvm": "allow", + "options": "-cpu host" }, "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", "version": "16.04.7.1", @@ -49,6 +58,14 @@ "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" }, + { + "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", "version": "1.0", @@ -59,6 +76,13 @@ } ], "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", "images": { diff --git a/gns3server/appliances/ubuntu-docker.gns3a b/gns3server/appliances/ubuntu-docker.gns3a index 110fba40..9cde03e7 100644 --- a/gns3server/appliances/ubuntu-docker.gns3a +++ b/gns3server/appliances/ubuntu-docker.gns3a @@ -14,7 +14,7 @@ "symbol": "linux_guest.svg", "docker": { "adapters": 1, - "image": "gns3/ubuntu:focal", + "image": "gns3/ubuntu:noble", "console_type": "telnet" } } diff --git a/gns3server/compute/docker/__init__.py b/gns3server/compute/docker/__init__.py index 69808a87..499d6784 100644 --- a/gns3server/compute/docker/__init__.py +++ b/gns3server/compute/docker/__init__.py @@ -28,6 +28,7 @@ import shutil import platformdirs from gns3server.utils import parse_version +from gns3server.config import Config from gns3server.utils.asyncio import locking from gns3server.compute.base_manager import BaseManager from gns3server.compute.docker.docker_vm import DockerVM @@ -95,8 +96,13 @@ class Docker(BaseManager): Get the Docker resources storage directory """ - appname = vendor = "GNS3" - docker_resources_dir = os.path.join(platformdirs.user_data_dir(appname, vendor, roaming=True), "docker", "resources") + resources_path = Config.instance().settings.Server.resources_path + if not resources_path: + appname = vendor = "GNS3" + 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) return docker_resources_dir diff --git a/gns3server/compute/qemu/qemu_vm.py b/gns3server/compute/qemu/qemu_vm.py index 24f1d8a8..35a1b89d 100644 --- a/gns3server/compute/qemu/qemu_vm.py +++ b/gns3server/compute/qemu/qemu_vm.py @@ -45,7 +45,7 @@ from ..nios.nio_tap import NIOTAP from ..base_node import BaseNode from ...utils.asyncio import monitor_process 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 gns3server.schemas.compute.qemu_nodes import Qemu, QemuPlatform @@ -54,6 +54,12 @@ import logging 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): module_name = "qemu" @@ -1855,14 +1861,17 @@ class QemuVM(BaseNode): if port: console_host = self._manager.port_manager.console_host if console_host == "0.0.0.0": - if socket.has_ipv6: - # to fix an issue with Qemu when IPv4 is not enabled - # see https://github.com/GNS3/gns3-gui/issues/2352 - # FIXME: consider making this more global (not just for Qemu + SPICE) - console_host = "::" - else: - raise QemuError("IPv6 must be enabled in order to use the SPICE console") - return ["-spice", f"addr={console_host},port={port},disable-ticketing", "-vga", "qxl"] + try: + if is_ipv6_enabled(): + # to fix an issue with Qemu when IPv4 is not enabled + # see https://github.com/GNS3/gns3-gui/issues/2352 + # FIXME: consider making this more global (not just for Qemu + SPICE) + console_host = "::" + except OSError as e: + raise QemuError("Could not check if IPv6 is enabled: {}".format(e)) + return ["-spice", + f"addr={console_host},port={port},disable-ticketing", + "-vga", "qxl"] else: return [] @@ -2640,9 +2649,16 @@ class QemuVM(BaseNode): command.extend(self._tpm_options()) if additional_options: try: - command.extend(shlex.split(additional_options)) + additional_opt_list = shlex.split(additional_options) except ValueError as 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) if self._console_type == "vnc": command.extend(['-machine', 'usb=on', '-device', 'usb-tablet']) diff --git a/gns3server/config_samples/gns3_server.conf b/gns3server/config_samples/gns3_server.conf index c69a8200..0a99ea33 100644 --- a/gns3server/config_samples/gns3_server.conf +++ b/gns3server/config_samples/gns3_server.conf @@ -34,7 +34,7 @@ enable_ssl = False certfile = /home/gns3/.config/GNS3/ssl/server.cert 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 ; Additional paths to look for images @@ -43,15 +43,20 @@ additional_images_paths = /opt/images;/mnt/disk1/images ; Path where user projects are stored 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 -; Path where custom device symbols are stored +; Path where custom user symbols are stored symbols_path = /home/gns3/GNS3/symbols ; Path where custom configs are stored 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 ; Currently available themes are "Classic", Affinity-square-blue", "Affinity-square-red" ; "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_builtin_templates = True +; Install built-in appliances +install_builtin_appliances = True + ; check if hardware virtualization is used by other emulators (KVM, VMware or VirtualBox) hardware_virtualization_check = True @@ -148,3 +156,5 @@ monitor_host = 127.0.0.1 enable_hardware_acceleration = True ; Require hardware acceleration in order to start VMs require_hardware_acceleration = False +; Allow unsafe additional command line options +allow_unsafe_options = False \ No newline at end of file diff --git a/gns3server/configs/iou_l2_base_startup-config.txt b/gns3server/configs/iou_l2_base_startup-config.txt index 4a09db82..0ce9f365 100644 --- a/gns3server/configs/iou_l2_base_startup-config.txt +++ b/gns3server/configs/iou_l2_base_startup-config.txt @@ -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 no ip cef -no ip domain-lookup +no ip domain lookup ! ! ! diff --git a/gns3server/configs/iou_l3_base_startup-config.txt b/gns3server/configs/iou_l3_base_startup-config.txt index 67628f77..2706875d 100644 --- a/gns3server/configs/iou_l3_base_startup-config.txt +++ b/gns3server/configs/iou_l3_base_startup-config.txt @@ -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 no ip cef -no ip domain-lookup +no ip domain lookup ! ! ip tcp synwait-time 5 diff --git a/gns3server/controller/__init__.py b/gns3server/controller/__init__.py index ca2622c9..6f82a42d 100644 --- a/gns3server/controller/__init__.py +++ b/gns3server/controller/__init__.py @@ -270,13 +270,18 @@ class Controller: log.error(f"Cannot read IOU license file '{iourc_path}': {e}") self._iou_license_settings["license_check"] = iou_config.license_check - previous_version = controller_vars.get("version") - log.info("Comparing controller version {} with config version {}".format(__version__, previous_version)) - if not previous_version or \ - parse_version(__version__.split("+")[0]) > parse_version(previous_version.split("+")[0]): - self._appliance_manager.install_builtin_appliances() - elif not os.listdir(self._appliance_manager.builtin_appliances_path()): - self._appliance_manager.install_builtin_appliances() + # install the built-in appliances if needed + if Config.instance().settings.Server.install_builtin_appliances: + previous_version = controller_vars.get("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 \ + parse_version(__version__.split("+")[0]) > parse_version(previous_version.split("+")[0]): + self._appliance_manager.install_builtin_appliances() + elif not os.listdir(builtin_appliances_path): + 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.load_appliances() diff --git a/gns3server/controller/appliance_manager.py b/gns3server/controller/appliance_manager.py index 99a3377b..d132fe19 100644 --- a/gns3server/controller/appliance_manager.py +++ b/gns3server/controller/appliance_manager.py @@ -100,8 +100,13 @@ class ApplianceManager: Get the built-in appliance storage directory """ - appname = vendor = "GNS3" - appliances_dir = os.path.join(platformdirs.user_data_dir(appname, vendor, roaming=True), "appliances") + resources_path = Config.instance().settings.Server.resources_path + if not resources_path: + appname = vendor = "GNS3" + 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: shutil.rmtree(appliances_dir, ignore_errors=True) os.makedirs(appliances_dir, exist_ok=True) diff --git a/gns3server/controller/export_project.py b/gns3server/controller/export_project.py index 9e14525c..7c0eb54e 100644 --- a/gns3server/controller/export_project.py +++ b/gns3server/controller/export_project.py @@ -39,7 +39,7 @@ async def export_project( temporary_dir, include_images=False, include_snapshots=False, - keep_compute_id=False, + keep_compute_ids=False, allow_all_nodes=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 include_images: save OS images 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 allow_all_nodes: Allow all nodes type to be include in the zip even if not portable - :param reset_mac_addresses: Reset MAC addresses for every nodes. + :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 included in the zip even if not portable + :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 @@ -77,7 +77,7 @@ async def export_project( os.path.join(project._path, file), zstream, include_images, - keep_compute_id, + keep_compute_ids, allow_all_nodes, temporary_dir, reset_mac_addresses, @@ -193,7 +193,7 @@ def _is_exportable(path, include_snapshots=False): 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. @@ -225,7 +225,7 @@ async def _patch_project_file( 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"])) - 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 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() == "": 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) if include_images is True: 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"][ "computes" ] = [] # Strip compute information because could contain secret info like password diff --git a/gns3server/controller/import_project.py b/gns3server/controller/import_project.py index 50b43ec9..49b59f8b 100644 --- a/gns3server/controller/import_project.py +++ b/gns3server/controller/import_project.py @@ -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): """ 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 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 keep_compute_id: If true do not touch the compute id + :param keep_compute_ids: keep compute IDs unchanged :returns: Project """ @@ -126,7 +126,7 @@ async def import_project(controller, project_id, stream, location=None, name=Non drawing["drawing_id"] = str(uuid.uuid4()) # 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 # unless it's a linux host without GNS3 VM if not sys.platform.startswith("linux") or controller.has_compute("vm"): diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index ee351dc1..80b9dd56 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -210,7 +210,11 @@ class Project: if os.path.exists(snapshot_dir): for snap in os.listdir(snapshot_dir): if snap.endswith(".gns3project"): - snapshot = Snapshot(self, filename=snap) + try: + snapshot = Snapshot(self, filename=snap) + except ValueError: + log.error("Invalid snapshot file: {}".format(snap)) + continue self._snapshots[snapshot.id] = snapshot # Create the project on demand on the compute node @@ -491,7 +495,7 @@ class Project: if base_name is 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: base_name = re.sub(r"[0-9]+$", "{0}", base_name) @@ -1087,7 +1091,7 @@ class Project: zstream, self, tmpdir, - keep_compute_id=True, + keep_compute_ids=True, allow_all_nodes=True, reset_mac_addresses=reset_mac_addresses, ) @@ -1106,7 +1110,7 @@ class Project: str(uuid.uuid4()), f, name=name, - keep_compute_id=True + keep_compute_ids=True ) log.info(f"Project '{project.name}' duplicated in {time.time() - begin:.4f} seconds") diff --git a/gns3server/controller/snapshot.py b/gns3server/controller/snapshot.py index ddeb3cbd..5491bcbb 100644 --- a/gns3server/controller/snapshot.py +++ b/gns3server/controller/snapshot.py @@ -59,14 +59,9 @@ class Snapshot: + ".gns3project" ) else: - self._name = filename.split("_")[0] + self._name = filename.rsplit("_", 2)[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() - ) - except ValueError: - self._created_at = datetime.now(timezone.utc) + self._created_at = (datetime.strptime(datestring, "%d%m%y_%H%M%S").replace(tzinfo=timezone.utc).timestamp()) self._path = os.path.join(project.path, "snapshots", filename) @property @@ -104,7 +99,7 @@ class Snapshot: with tempfile.TemporaryDirectory(dir=snapshot_directory) as tmpdir: # Do not compress the snapshots 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 for chunk in zstream: await f.write(chunk) diff --git a/gns3server/controller/topology.py b/gns3server/controller/topology.py index f6d3b039..a336aee9 100644 --- a/gns3server/controller/topology.py +++ b/gns3server/controller/topology.py @@ -35,6 +35,7 @@ from .drawing import Drawing from .node import Node 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.compute.dynamips_nodes import DynamipsCreate @@ -43,7 +44,7 @@ import logging log = logging.getLogger(__name__) -GNS3_FILE_FORMAT_REVISION = 9 +GNS3_FILE_FORMAT_REVISION = 10 class DynamipsNodeValidation(DynamipsCreate): @@ -186,6 +187,10 @@ def load_topology(path): if variables: 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: _check_topology_schema(topo, path) except ControllerError as e: @@ -201,6 +206,30 @@ def load_topology(path): 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): """ Convert topologies from GNS3 2.1.x to 2.2 diff --git a/gns3server/crash_report.py b/gns3server/crash_report.py index 12a5de67..b4d0d9de 100644 --- a/gns3server/crash_report.py +++ b/gns3server/crash_report.py @@ -58,7 +58,7 @@ class CrashReport: 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 def __init__(self): diff --git a/gns3server/schemas/config.py b/gns3server/schemas/config.py index 6e57aef8..f6e1daab 100644 --- a/gns3server/schemas/config.py +++ b/gns3server/schemas/config.py @@ -69,6 +69,7 @@ class QemuSettings(BaseModel): monitor_host: str = "127.0.0.1" enable_hardware_acceleration: bool = True require_hardware_acceleration: bool = False + allow_unsafe_options: bool = False model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True) @@ -126,6 +127,7 @@ class ServerSettings(BaseModel): appliances_path: str = "~/GNS3/appliances" symbols_path: str = "~/GNS3/symbols" configs_path: str = "~/GNS3/configs" + resources_path: str = None default_symbol_theme: BuiltinSymbolTheme = BuiltinSymbolTheme.affinity_square_blue allow_raw_images: bool = True auto_discover_images: bool = True @@ -144,6 +146,7 @@ class ServerSettings(BaseModel): default_nat_interface: str = None allow_remote_console: bool = False enable_builtin_templates: bool = True + install_builtin_appliances: bool = True model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True, use_enum_values=True) @field_validator("additional_images_paths", mode="before") diff --git a/gns3server/static/web-ui/index.html b/gns3server/static/web-ui/index.html index ef44affc..6fb2fa0b 100644 --- a/gns3server/static/web-ui/index.html +++ b/gns3server/static/web-ui/index.html @@ -36,7 +36,7 @@