mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-24 17:28:08 +00:00
Merge branch '2.2' into 3.0
# Conflicts: # CHANGELOG # docs/api/notifications/link.updated.json # docs/api/notifications/log.warning.json # docs/api/v2/compute/ethernet_switch/projectsprojectidethernetswitchnodes.rst # docs/api/v2/compute/ethernet_switch/projectsprojectidethernetswitchnodesnodeid.rst # docs/api/v2/compute/iou/projectsprojectidiounodes.rst # docs/api/v2/compute/project/projects.rst # docs/api/v2/compute/qemu/projectsprojectidqemunodes.rst # docs/api/v2/compute/qemu/projectsprojectidqemunodesnodeid.rst # docs/api/v2/compute/qemu/projectsprojectidqemunodesnodeidstart.rst # docs/api/v2/controller/link/projectsprojectidlinks.rst # docs/api/v2/controller/link/projectsprojectidlinkslinkid.rst # docs/api/v2/controller/link/projectsprojectidlinkslinkidstartcapture.rst # docs/api/v2/controller/project/projects.rst # docs/api/v2/controller/project/projectsprojectidduplicate.rst # docs/controller_notifications.rst # docs/curl.rst # docs/gns3_file.json # docs/project_notifications.rst # gns3server/compute/qemu/qemu_vm.py # gns3server/controller/project.py # gns3server/crash_report.py # gns3server/schemas/ethernet_hub.py # gns3server/schemas/ethernet_switch.py # gns3server/static/web-ui/3rdpartylicenses.txt # gns3server/static/web-ui/index.html # gns3server/utils/asyncio/telnet_server.py # gns3server/version.py # gns3server/web/web_server.py # requirements.txt # tests/controller/test_project.py # tests/controller/test_topology.py # tests/handlers/api/controller/test_project.py
This commit is contained in:
commit
0037f31553
@ -18,7 +18,7 @@ jobs:
|
|||||||
ref: "gh-pages"
|
ref: "gh-pages"
|
||||||
- uses: actions/setup-python@v3
|
- uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.8
|
||||||
- name: Merge changes from 3.0 branch
|
- name: Merge changes from 3.0 branch
|
||||||
run: |
|
run: |
|
||||||
git config user.name github-actions
|
git config user.name github-actions
|
||||||
|
11
CHANGELOG
11
CHANGELOG
@ -1,5 +1,16 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 2.2.45 12/01/2024
|
||||||
|
|
||||||
|
* Bundle web-ui v2.2.45
|
||||||
|
* Fix mouse offset issues with VNC in Qemu. Fixes #2335
|
||||||
|
* Add project.created, project.opened and project.deleted controller notification stream. Move project.updated and project.closed from project notification to controller notification stream.
|
||||||
|
* Do not stop searching for Qemu binaries if one binary cannot be executed. Ref #2306
|
||||||
|
* Fix Ethernet switch and Ethernet hub port validations. Fixes #2334
|
||||||
|
* Update CORS policy
|
||||||
|
* Add custom executable paths on Windows
|
||||||
|
* Upgrade sentry-sdk and aiohttp
|
||||||
|
|
||||||
## 3.0.0b1 27/11/2023
|
## 3.0.0b1 27/11/2023
|
||||||
|
|
||||||
* Bundle web-ui v3.0.0b1
|
* Bundle web-ui v3.0.0b1
|
||||||
|
3
docs/api/notifications/node.deleted.json
Normal file
3
docs/api/notifications/node.deleted.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"a": "b"
|
||||||
|
}
|
3
docs/api/notifications/node.updated.json
Normal file
3
docs/api/notifications/node.updated.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"a": "b"
|
||||||
|
}
|
21
docs/api/notifications/project.created.json
Normal file
21
docs/api/notifications/project.created.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"auto_close": true,
|
||||||
|
"auto_open": false,
|
||||||
|
"auto_start": false,
|
||||||
|
"drawing_grid_size": 25,
|
||||||
|
"filename": "Test.gns3",
|
||||||
|
"grid_size": 75,
|
||||||
|
"name": "Test",
|
||||||
|
"path": "/tmp/tmprusds8mt/projects/87d4b692-52b4-4b4c-8828-13666306a68a",
|
||||||
|
"project_id": "87d4b692-52b4-4b4c-8828-13666306a68a",
|
||||||
|
"scene_height": 1000,
|
||||||
|
"scene_width": 2000,
|
||||||
|
"show_grid": false,
|
||||||
|
"show_interface_labels": false,
|
||||||
|
"show_layers": false,
|
||||||
|
"snap_to_grid": false,
|
||||||
|
"status": "opened",
|
||||||
|
"supplier": null,
|
||||||
|
"variables": null,
|
||||||
|
"zoom": 100
|
||||||
|
}
|
21
docs/api/notifications/project.deleted.json
Normal file
21
docs/api/notifications/project.deleted.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"auto_close": true,
|
||||||
|
"auto_open": false,
|
||||||
|
"auto_start": false,
|
||||||
|
"drawing_grid_size": 25,
|
||||||
|
"filename": "Test.gns3",
|
||||||
|
"grid_size": 75,
|
||||||
|
"name": "Test",
|
||||||
|
"path": "/tmp/tmpvqf8d5mx/projects/6f01ee8c-5fe7-47a2-95ab-a0f4c0a355f9",
|
||||||
|
"project_id": "6f01ee8c-5fe7-47a2-95ab-a0f4c0a355f9",
|
||||||
|
"scene_height": 1000,
|
||||||
|
"scene_width": 2000,
|
||||||
|
"show_grid": false,
|
||||||
|
"show_interface_labels": false,
|
||||||
|
"show_layers": false,
|
||||||
|
"snap_to_grid": false,
|
||||||
|
"status": "closed",
|
||||||
|
"supplier": null,
|
||||||
|
"variables": null,
|
||||||
|
"zoom": 100
|
||||||
|
}
|
21
docs/api/notifications/project.opened.json
Normal file
21
docs/api/notifications/project.opened.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"auto_close": true,
|
||||||
|
"auto_open": false,
|
||||||
|
"auto_start": false,
|
||||||
|
"drawing_grid_size": 25,
|
||||||
|
"filename": "test.gns3",
|
||||||
|
"grid_size": 75,
|
||||||
|
"name": "test",
|
||||||
|
"path": "/tmp/tmp7swwxptj/projects/e5b0b37a-a74e-40a2-9adb-42908f146fba",
|
||||||
|
"project_id": "e5b0b37a-a74e-40a2-9adb-42908f146fba",
|
||||||
|
"scene_height": 1000,
|
||||||
|
"scene_width": 2000,
|
||||||
|
"show_grid": false,
|
||||||
|
"show_interface_labels": false,
|
||||||
|
"show_layers": false,
|
||||||
|
"snap_to_grid": false,
|
||||||
|
"status": "opened",
|
||||||
|
"supplier": null,
|
||||||
|
"variables": null,
|
||||||
|
"zoom": 100
|
||||||
|
}
|
@ -11,7 +11,7 @@
|
|||||||
"status": "stable",
|
"status": "stable",
|
||||||
"maintainer": "GNS3 Team",
|
"maintainer": "GNS3 Team",
|
||||||
"maintainer_email": "developers@gns3.net",
|
"maintainer_email": "developers@gns3.net",
|
||||||
"usage": "Configure interfaces in /opt/bootlocal.sh, BIRD configuration is done in /usr/local/etc/bird",
|
"usage": "\n*** BIRD v1 is end-of-life ***\nPlease use the BIRD2 appliance.\n\nConfigure interfaces in /opt/bootlocal.sh, BIRD configuration is done in /usr/local/etc/bird",
|
||||||
"qemu": {
|
"qemu": {
|
||||||
"adapter_type": "e1000",
|
"adapter_type": "e1000",
|
||||||
"adapters": 4,
|
"adapters": 4,
|
||||||
|
@ -26,6 +26,13 @@
|
|||||||
"kvm": "require"
|
"kvm": "require"
|
||||||
},
|
},
|
||||||
"images": [
|
"images": [
|
||||||
|
{
|
||||||
|
"filename": "asav9-18-2.qcow2",
|
||||||
|
"version": "9.18.2 CML",
|
||||||
|
"md5sum": "6f10fe106edfad9163625770a47a6b73",
|
||||||
|
"filesize": 340262912,
|
||||||
|
"download_url": "https://learningnetworkstore.cisco.com/cisco-modeling-labs-personal/cisco-modeling-labs-personal/CML-PERSONAL.html"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename": "asav9-16-2.qcow2",
|
"filename": "asav9-16-2.qcow2",
|
||||||
"version": "9.16.2 CML",
|
"version": "9.16.2 CML",
|
||||||
@ -119,6 +126,12 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"name": "9.18.2 CML",
|
||||||
|
"images": {
|
||||||
|
"hda_disk_image": "asav9-18-2.qcow2"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "9.16.2 CML",
|
"name": "9.16.2 CML",
|
||||||
"images": {
|
"images": {
|
||||||
|
@ -24,6 +24,13 @@
|
|||||||
"kvm": "require"
|
"kvm": "require"
|
||||||
},
|
},
|
||||||
"images": [
|
"images": [
|
||||||
|
{
|
||||||
|
"filename": "c8000v-universalk9_8G_serial.17.09.01a.qcow2",
|
||||||
|
"version": "17.09.01a 8G",
|
||||||
|
"md5sum": "a10ae2c4d71f4eb611bc4d83ad7709f0",
|
||||||
|
"filesize": 1856634880,
|
||||||
|
"download_url": "https://software.cisco.com/download/home/286327102/type/282046477/release/Bengaluru-17.6.5"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename": "c8000v-universalk9_8G_serial.17.06.05.qcow2",
|
"filename": "c8000v-universalk9_8G_serial.17.06.05.qcow2",
|
||||||
"version": "17.06.05 8G",
|
"version": "17.06.05 8G",
|
||||||
@ -54,6 +61,12 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"name": "17.09.01a 8G",
|
||||||
|
"images": {
|
||||||
|
"hda_disk_image": "c8000v-universalk9_8G_serial.17.09.01a.qcow2"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "17.06.05 8G",
|
"name": "17.06.05 8G",
|
||||||
"images": {
|
"images": {
|
||||||
|
@ -24,6 +24,13 @@
|
|||||||
"kvm": "require"
|
"kvm": "require"
|
||||||
},
|
},
|
||||||
"images": [
|
"images": [
|
||||||
|
{
|
||||||
|
"filename": "csr1000v-universalk9.17.03.06-serial.qcow2",
|
||||||
|
"version": "17.03.06",
|
||||||
|
"md5sum": "086ab9bef6e66de847af0da3910c60e8",
|
||||||
|
"filesize": 1422000128,
|
||||||
|
"download_url": "https://software.cisco.com/download/home/284364978/type/282046477/release/Gibraltar-16.12.3"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename": "csr1000v-universalk9.16.12.03-serial.qcow2",
|
"filename": "csr1000v-universalk9.16.12.03-serial.qcow2",
|
||||||
"version": "16.12.3",
|
"version": "16.12.3",
|
||||||
@ -159,6 +166,12 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"name": "17.03.06",
|
||||||
|
"images": {
|
||||||
|
"hda_disk_image": "csr1000v-universalk9.17.03.06-serial.qcow2"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "16.12.3",
|
"name": "16.12.3",
|
||||||
"images": {
|
"images": {
|
||||||
|
@ -26,6 +26,13 @@
|
|||||||
"options": "-smp 4 -cpu host"
|
"options": "-smp 4 -cpu host"
|
||||||
},
|
},
|
||||||
"images": [
|
"images": [
|
||||||
|
{
|
||||||
|
"filename": "xrv9k-fullk9-x-7.7.1.qcow2",
|
||||||
|
"version": "7.7.1",
|
||||||
|
"md5sum": "682fff40d2ff373d8da3342906553b54",
|
||||||
|
"filesize": 1643905024,
|
||||||
|
"download_url": "https://software.cisco.com/download/home/286288939/type/280805694/release/7.1.1"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename": "xrv9k-fullk9-x-7.1.1.qcow2",
|
"filename": "xrv9k-fullk9-x-7.1.1.qcow2",
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
@ -105,6 +112,12 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"name": "7.7.1",
|
||||||
|
"images": {
|
||||||
|
"hda_disk_image": "xrv9k-fullk9-x-7.7.1.qcow2"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "7.1.1",
|
"name": "7.1.1",
|
||||||
"images": {
|
"images": {
|
||||||
|
@ -26,6 +26,13 @@
|
|||||||
"kvm": "require"
|
"kvm": "require"
|
||||||
},
|
},
|
||||||
"images": [
|
"images": [
|
||||||
|
{
|
||||||
|
"filename": "nexus9300v64.10.3.1.F.qcow2",
|
||||||
|
"version": "9300v 10.3.1.F",
|
||||||
|
"md5sum": "a6ffd2501a5791c11cee319943b912da",
|
||||||
|
"filesize": 2097086464,
|
||||||
|
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/10.1(1)"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename": "nexus9500v64.10.1.1.qcow2",
|
"filename": "nexus9500v64.10.1.1.qcow2",
|
||||||
"version": "9500v 10.1.1",
|
"version": "9500v 10.1.1",
|
||||||
@ -198,6 +205,13 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"name": "9300v 10.3.1.F",
|
||||||
|
"images": {
|
||||||
|
"bios_image": "OVMF-edk2-stable202305.fd",
|
||||||
|
"hda_disk_image": "nexus9300v64.10.3.1.F.qcow2"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "9500v 10.1.1",
|
"name": "9500v 10.1.1",
|
||||||
"images": {
|
"images": {
|
||||||
|
@ -24,12 +24,12 @@
|
|||||||
},
|
},
|
||||||
"images": [
|
"images": [
|
||||||
{
|
{
|
||||||
"filename": "debian-12.2.qcow2",
|
"filename": "debian-12.4.qcow2",
|
||||||
"version": "12.2",
|
"version": "12.4",
|
||||||
"md5sum": "adf7716ec4a4e4e9e5ccfc7a1d7bd103",
|
"md5sum": "adcf7fdc25e10b3d2d9e2ef91168bffd",
|
||||||
"filesize": 286654464,
|
"filesize": 286179840,
|
||||||
"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.2.qcow2"
|
"direct_download_url": "https://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/debian-12.4.qcow2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "debian-11.8.qcow2",
|
"filename": "debian-11.8.qcow2",
|
||||||
@ -42,9 +42,9 @@
|
|||||||
],
|
],
|
||||||
"versions": [
|
"versions": [
|
||||||
{
|
{
|
||||||
"name": "12.2",
|
"name": "12.4",
|
||||||
"images": {
|
"images": {
|
||||||
"hda_disk_image": "debian-12.2.qcow2"
|
"hda_disk_image": "debian-12.4.qcow2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -11,26 +11,36 @@
|
|||||||
"status": "experimental",
|
"status": "experimental",
|
||||||
"maintainer": "GNS3 Team",
|
"maintainer": "GNS3 Team",
|
||||||
"maintainer_email": "developers@gns3.net",
|
"maintainer_email": "developers@gns3.net",
|
||||||
"usage": "Make sure the Boot priority of the configuration template is HDD or CD.\n\nAbort the BCM process and format the flash after first boot by entering these commands:\nen\nformat flash:\n\nSometimes the flash device is not available after boot.",
|
"usage": "Make sure the Boot priority of the configuration template is HDD or CD.\n\nFor FTOS 9.8, switch to vnc console, start the device, abort the BMP process and format the flash after first boot by entering these commands:\nen\nformat flash:\n\nSometimes the flash device is not available after boot.",
|
||||||
"first_port_name": "Management0/0",
|
"first_port_name": "Management0/0",
|
||||||
"port_name_format": "fortyGigE0/{0}",
|
"port_name_format": "fortyGigE0/{0}",
|
||||||
"qemu": {
|
"qemu": {
|
||||||
"adapter_type": "e1000",
|
"adapter_type": "e1000",
|
||||||
"adapters": 6,
|
"adapters": 6,
|
||||||
"ram": 512,
|
"ram": 1024,
|
||||||
"hda_disk_interface": "ide",
|
"hda_disk_interface": "ide",
|
||||||
"arch": "i386",
|
"arch": "i386",
|
||||||
"console_type": "vnc",
|
"console_type": "telnet",
|
||||||
"boot_priority": "cd",
|
"boot_priority": "cd",
|
||||||
"kvm": "require"
|
"kvm": "require"
|
||||||
},
|
},
|
||||||
"images": [
|
"images": [
|
||||||
|
{
|
||||||
|
"filename": "FTOS-SI-9.13.0.0.iso",
|
||||||
|
"version": "9.13.0",
|
||||||
|
"md5sum": "8418049e451c76e7b85e36eca0a0a730",
|
||||||
|
"filesize": 131278848,
|
||||||
|
"download_url": "https://www.dell.com/support/kbdoc/en-us/000184062/ftos-for-s-series-os-emulator-current-release-evaluation-version",
|
||||||
|
"direct_download_url": "https://downloads.dell.com/translatedpdf/force10/os9/FTOS-SI-9.13.0.0.zip",
|
||||||
|
"compression": "zip"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename": "FTOS-SI-9.8.0.0.iso",
|
"filename": "FTOS-SI-9.8.0.0.iso",
|
||||||
"version": "9.8.0",
|
"version": "9.8.0",
|
||||||
"md5sum": "b9b50eda0a73407dc381792ff7975e24",
|
"md5sum": "b9b50eda0a73407dc381792ff7975e24",
|
||||||
"filesize": 108115968,
|
"filesize": 108115968,
|
||||||
"download_url": "https://www.force10networks.com/CSPortal20/Software/SSeriesDownloads.aspx",
|
"download_url": "https://www.dell.com/support/kbdoc/en-us/000184062/ftos-for-s-series-os-emulator-current-release-evaluation-version",
|
||||||
|
"direct_download_url": "https://downloads.dell.com/translatedpdf/force10/os9/FTOS-SI-9.8.0.0.zip",
|
||||||
"compression": "zip"
|
"compression": "zip"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -43,6 +53,13 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"name": "9.13.0",
|
||||||
|
"images": {
|
||||||
|
"hda_disk_image": "empty30G.qcow2",
|
||||||
|
"cdrom_image": "FTOS-SI-9.13.0.0.iso"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "9.8.0",
|
"name": "9.8.0",
|
||||||
"images": {
|
"images": {
|
||||||
|
@ -26,6 +26,14 @@
|
|||||||
"options": "-nographic"
|
"options": "-nographic"
|
||||||
},
|
},
|
||||||
"images": [
|
"images": [
|
||||||
|
{
|
||||||
|
"filename": "Fedora-Cloud-Base-39-1.5.x86_64.qcow2",
|
||||||
|
"version": "39-1.5",
|
||||||
|
"md5sum": "800a10df2d369891ed65900bcacacd47",
|
||||||
|
"filesize": 544604160,
|
||||||
|
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/39/Cloud/x86_64/images",
|
||||||
|
"direct_download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/39/Cloud/x86_64/images/Fedora-Cloud-Base-39-1.5.x86_64.qcow2"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename": "Fedora-Cloud-Base-38-1.6.x86_64.qcow2",
|
"filename": "Fedora-Cloud-Base-38-1.6.x86_64.qcow2",
|
||||||
"version": "38-1.6",
|
"version": "38-1.6",
|
||||||
@ -34,30 +42,6 @@
|
|||||||
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/38/Cloud/x86_64/images",
|
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/38/Cloud/x86_64/images",
|
||||||
"direct_download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/38/Cloud/x86_64/images/Fedora-Cloud-Base-38-1.6.x86_64.qcow2"
|
"direct_download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/38/Cloud/x86_64/images/Fedora-Cloud-Base-38-1.6.x86_64.qcow2"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"filename": "Fedora-Cloud-Base-37-1.7.x86_64.qcow2",
|
|
||||||
"version": "37-1.7",
|
|
||||||
"md5sum": "36f7b464b6ab46ad97c001b539495e90",
|
|
||||||
"filesize": 492830720,
|
|
||||||
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/37/Cloud/x86_64/images",
|
|
||||||
"direct_download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/37/Cloud/x86_64/images/Fedora-Cloud-Base-37-1.7.x86_64.qcow2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "Fedora-Cloud-Base-36-1.5.x86_64.qcow2",
|
|
||||||
"version": "36-1.5",
|
|
||||||
"md5sum": "7f7cdad25b77f232078bf454c39529d3",
|
|
||||||
"filesize": 448266240,
|
|
||||||
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/36/Cloud/x86_64/images",
|
|
||||||
"direct_download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/36/Cloud/x86_64/images/Fedora-Cloud-Base-36-1.5.x86_64.qcow2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "Fedora-Cloud-Base-35-1.2.x86_64.qcow2",
|
|
||||||
"version": "35-1.2",
|
|
||||||
"md5sum": "cfa9cdcfb946e5f4cf9dd4d7906008d0",
|
|
||||||
"filesize": 376897536,
|
|
||||||
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/35/Cloud/x86_64/images",
|
|
||||||
"direct_download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/35/Cloud/x86_64/images/Fedora-Cloud-Base-35-1.2.x86_64.qcow2"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"filename": "fedora-cloud-init-data.iso",
|
"filename": "fedora-cloud-init-data.iso",
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
@ -68,33 +52,19 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"name": "39-1.5",
|
||||||
|
"images": {
|
||||||
|
"hda_disk_image": "Fedora-Cloud-Base-39-1.5.x86_64.qcow2",
|
||||||
|
"cdrom_image": "fedora-cloud-init-data.iso"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "38-1.6",
|
"name": "38-1.6",
|
||||||
"images": {
|
"images": {
|
||||||
"hda_disk_image": "Fedora-Cloud-Base-38-1.6.x86_64.qcow2",
|
"hda_disk_image": "Fedora-Cloud-Base-38-1.6.x86_64.qcow2",
|
||||||
"cdrom_image": "fedora-cloud-init-data.iso"
|
"cdrom_image": "fedora-cloud-init-data.iso"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "37-1.7",
|
|
||||||
"images": {
|
|
||||||
"hda_disk_image": "Fedora-Cloud-Base-37-1.7.x86_64.qcow2",
|
|
||||||
"cdrom_image": "fedora-cloud-init-data.iso"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "36-1.5",
|
|
||||||
"images": {
|
|
||||||
"hda_disk_image": "Fedora-Cloud-Base-36-1.5.x86_64.qcow2",
|
|
||||||
"cdrom_image": "fedora-cloud-init-data.iso"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "35-1.2",
|
|
||||||
"images": {
|
|
||||||
"hda_disk_image": "Fedora-Cloud-Base-35-1.2.x86_64.qcow2",
|
|
||||||
"cdrom_image": "fedora-cloud-init-data.iso"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,65 @@
|
|||||||
"vendor_url": "https://www.huawei.com",
|
"vendor_url": "https://www.huawei.com",
|
||||||
"product_name": "HuaWei NE40E",
|
"product_name": "HuaWei NE40E",
|
||||||
"product_url": "https://e.huawei.com/en/products/enterprise-networking/routers/ne/ne40e",
|
"product_url": "https://e.huawei.com/en/products/enterprise-networking/routers/ne/ne40e",
|
||||||
"registry_version": 4,
|
"registry_version": 6,
|
||||||
"status": "experimental",
|
"status": "experimental",
|
||||||
"availability": "service-contract",
|
"availability": "service-contract",
|
||||||
"maintainer": "none",
|
"maintainer": "none",
|
||||||
"maintainer_email": "",
|
"maintainer_email": "",
|
||||||
"first_port_name": "eth0",
|
|
||||||
"port_name_format": "Ethernet1/0/{0}",
|
"port_name_format": "Ethernet1/0/{0}",
|
||||||
"qemu": {
|
"qemu": {
|
||||||
"adapter_type": "e1000",
|
"adapter_type": "e1000",
|
||||||
"adapters": 12,
|
"adapters": 12,
|
||||||
|
"custom_adapters": [
|
||||||
|
{
|
||||||
|
"adapter_number": 0,
|
||||||
|
"port_name": "Gi0/0/0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter_number": 1,
|
||||||
|
"port_name": "Mgmt0/0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter_number": 2,
|
||||||
|
"port_name": "Ethernet1/0/0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter_number": 3,
|
||||||
|
"port_name": "Ethernet1/0/1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter_number": 4,
|
||||||
|
"port_name": "Ethernet1/0/2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter_number": 5,
|
||||||
|
"port_name": "Ethernet1/0/3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter_number": 6,
|
||||||
|
"port_name": "Ethernet1/0/4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter_number": 7,
|
||||||
|
"port_name": "Ethernet1/0/5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter_number": 8,
|
||||||
|
"port_name": "Ethernet1/0/6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter_number": 9,
|
||||||
|
"port_name": "Ethernet1/0/7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter_number": 10,
|
||||||
|
"port_name": "Ethernet1/0/8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"adapter_number": 11,
|
||||||
|
"port_name": "Ethernet1/0/9"
|
||||||
|
}
|
||||||
|
],
|
||||||
"ram": 2048,
|
"ram": 2048,
|
||||||
"cpus": 2,
|
"cpus": 2,
|
||||||
"hda_disk_interface": "ide",
|
"hda_disk_interface": "ide",
|
||||||
|
@ -30,6 +30,13 @@
|
|||||||
"options": "-vga std -usbdevice tablet"
|
"options": "-vga std -usbdevice tablet"
|
||||||
},
|
},
|
||||||
"images": [
|
"images": [
|
||||||
|
{
|
||||||
|
"version": "1.3.0",
|
||||||
|
"filename": "ostinatostd-1.3.0-1.qcow2",
|
||||||
|
"filesize": 173735936,
|
||||||
|
"md5sum": "ff25fed989c43aeac84bf0d542ad43ba",
|
||||||
|
"download_url": "https://ostinato.org/pricing/gns3"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename": "ostinatostd-1.2.0-1.qcow2",
|
"filename": "ostinatostd-1.2.0-1.qcow2",
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@ -46,6 +53,12 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"name": "1.3.0",
|
||||||
|
"images": {
|
||||||
|
"hda_disk_image": "ostinatostd-1.3.0-1.qcow2"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "1.2.0",
|
"name": "1.2.0",
|
||||||
"images": {
|
"images": {
|
||||||
|
@ -11,9 +11,9 @@
|
|||||||
"registry_version": 4,
|
"registry_version": 4,
|
||||||
"status": "stable",
|
"status": "stable",
|
||||||
"availability": "service-contract",
|
"availability": "service-contract",
|
||||||
"maintainer": "Neyder Achahuanco",
|
"maintainer": "Da-Geek",
|
||||||
"maintainer_email": "neyder@neyder.net",
|
"maintainer_email": "dageek@dageeks-geeks.gg",
|
||||||
"usage": "You should download Red Hat Enterprise Linux KVM Guest Image from https://access.redhat.com/downloads/content/479/ver=/rhel---9/9.2/x86_64/product-software attach/customize cloud-init.iso and start.\nusername: cloud-user\npassword: redhat",
|
"usage": "You should download Red Hat Enterprise Linux KVM Guest Image from https://access.redhat.com/downloads/content/479/ver=/rhel---9/9.3/x86_64/product-software attach/customize rhel-cloud-init.iso and start.\nusername: cloud-user\npassword: redhat",
|
||||||
"qemu": {
|
"qemu": {
|
||||||
"adapter_type": "virtio-net-pci",
|
"adapter_type": "virtio-net-pci",
|
||||||
"adapters": 1,
|
"adapters": 1,
|
||||||
@ -26,6 +26,13 @@
|
|||||||
"options": "-cpu host -nographic"
|
"options": "-cpu host -nographic"
|
||||||
},
|
},
|
||||||
"images": [
|
"images": [
|
||||||
|
{
|
||||||
|
"filename": "rhel-9.3-x86_64-kvm.qcow2",
|
||||||
|
"version": "9.3",
|
||||||
|
"md5sum": "409d8d15f5177db2617b0e3e02139b5c",
|
||||||
|
"filesize": 858193920,
|
||||||
|
"download_url": "https://access.redhat.com/downloads/content/479/ver=/rhel---9/9.3/x86_64/product-software"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename": "rhel-9.2-x86_64-kvm.qcow2",
|
"filename": "rhel-9.2-x86_64-kvm.qcow2",
|
||||||
"version": "9.2",
|
"version": "9.2",
|
||||||
@ -112,6 +119,13 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"name": "9.3",
|
||||||
|
"images": {
|
||||||
|
"hda_disk_image": "rhel-9.3-x86_64-kvm.qcow2",
|
||||||
|
"cdrom_image": "rhel-cloud-init.iso"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "9.2",
|
"name": "9.2",
|
||||||
"images": {
|
"images": {
|
||||||
|
@ -26,6 +26,14 @@
|
|||||||
"options": "-nographic -cpu host"
|
"options": "-nographic -cpu host"
|
||||||
},
|
},
|
||||||
"images": [
|
"images": [
|
||||||
|
{
|
||||||
|
"filename": "Rocky-9-GenericCloud-Base-9.3-20231113.0.x86_64.qcow2",
|
||||||
|
"version": "9.3",
|
||||||
|
"md5sum": "48cdeb033364af5909e15ee48d0e144d",
|
||||||
|
"filesize": 1083965440,
|
||||||
|
"download_url": "https://download.rockylinux.org/pub/rocky/9/images/x86_64/",
|
||||||
|
"direct_download_url": "https://download.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-Base-9.3-20231113.0.x86_64.qcow2"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename": "Rocky-9-GenericCloud-Base-9.2-20230513.0.x86_64.qcow2",
|
"filename": "Rocky-9-GenericCloud-Base-9.2-20230513.0.x86_64.qcow2",
|
||||||
"version": "9.2",
|
"version": "9.2",
|
||||||
@ -34,6 +42,14 @@
|
|||||||
"download_url": "https://download.rockylinux.org/pub/rocky/9/images/x86_64/",
|
"download_url": "https://download.rockylinux.org/pub/rocky/9/images/x86_64/",
|
||||||
"direct_download_url": "https://download.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-Base-9.2-20230513.0.x86_64.qcow2"
|
"direct_download_url": "https://download.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-Base-9.2-20230513.0.x86_64.qcow2"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"filename": "Rocky-8-GenericCloud-Base-8.9-20231119.0.x86_64.qcow2",
|
||||||
|
"version": "8.9",
|
||||||
|
"md5sum": "50c44d8d9c4df43694372c13768f114c",
|
||||||
|
"filesize": 1971978240,
|
||||||
|
"download_url": "https://download.rockylinux.org/pub/rocky/8/images/x86_64/",
|
||||||
|
"direct_download_url": "https://download.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-GenericCloud-Base-8.9-20231119.0.x86_64.qcow2"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filename": "Rocky-8-GenericCloud-Base-8.8-20230518.0.x86_64.qcow2",
|
"filename": "Rocky-8-GenericCloud-Base-8.8-20230518.0.x86_64.qcow2",
|
||||||
"version": "8.8",
|
"version": "8.8",
|
||||||
@ -52,6 +68,13 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"name": "9.3",
|
||||||
|
"images": {
|
||||||
|
"hda_disk_image": "Rocky-9-GenericCloud-Base-9.3-20231113.0.x86_64.qcow2",
|
||||||
|
"cdrom_image": "rocky-cloud-init-data.iso"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "9.2",
|
"name": "9.2",
|
||||||
"images": {
|
"images": {
|
||||||
@ -59,6 +82,13 @@
|
|||||||
"cdrom_image": "rocky-cloud-init-data.iso"
|
"cdrom_image": "rocky-cloud-init-data.iso"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "8.9",
|
||||||
|
"images": {
|
||||||
|
"hda_disk_image": "Rocky-8-GenericCloud-Base-8.9-20231119.0.x86_64.qcow2",
|
||||||
|
"cdrom_image": "rocky-cloud-init-data.iso"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "8.8",
|
"name": "8.8",
|
||||||
"images": {
|
"images": {
|
||||||
|
@ -28,12 +28,12 @@
|
|||||||
},
|
},
|
||||||
"images": [
|
"images": [
|
||||||
{
|
{
|
||||||
"filename": "ubuntu-23.04-server-cloudimg-arm64.img",
|
"filename": "ubuntu-23.04-server-cloudimg-amd64.img",
|
||||||
"version": "Ubuntu 23.04 (Lunar Lobster)",
|
"version": "Ubuntu 23.04 (Lunar Lobster)",
|
||||||
"md5sum": "35fa3b31b65717af6f0520a769aac8c0",
|
"md5sum": "369e3b1f68416c39245a8014172406dd",
|
||||||
"filesize": 786432000,
|
"filesize": 756678656,
|
||||||
"download_url": "https://cloud-images.ubuntu.com/releases/23.04/release/",
|
"download_url": "https://cloud-images.ubuntu.com/releases/23.04/release/",
|
||||||
"direct_download_url": "https://cloud-images.ubuntu.com/releases/23.04/release/ubuntu-23.04-server-cloudimg-arm64.img"
|
"direct_download_url": "https://cloud-images.ubuntu.com/releases/23.04/release/ubuntu-23.04-server-cloudimg-amd64.img"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "ubuntu-22.04-server-cloudimg-amd64.img",
|
"filename": "ubuntu-22.04-server-cloudimg-amd64.img",
|
||||||
@ -72,7 +72,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Ubuntu 23.04 (Lunar Lobster)",
|
"name": "Ubuntu 23.04 (Lunar Lobster)",
|
||||||
"images": {
|
"images": {
|
||||||
"hda_disk_image": "ubuntu-23.04-server-cloudimg-arm64.img",
|
"hda_disk_image": "ubuntu-23.04-server-cloudimg-amd64.img",
|
||||||
"cdrom_image": "ubuntu-cloud-init-data.iso"
|
"cdrom_image": "ubuntu-cloud-init-data.iso"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -149,13 +149,20 @@ class Qemu(BaseManager):
|
|||||||
for arch in archs:
|
for arch in archs:
|
||||||
if f.endswith(arch) or f.endswith(f"{arch}.exe") or f.endswith(f"{arch}w.exe"):
|
if f.endswith(arch) or f.endswith(f"{arch}.exe") or f.endswith(f"{arch}w.exe"):
|
||||||
qemu_path = os.path.join(path, f)
|
qemu_path = os.path.join(path, f)
|
||||||
version = await Qemu.get_qemu_version(qemu_path)
|
try:
|
||||||
|
version = await Qemu.get_qemu_version(qemu_path)
|
||||||
|
except QemuError as e:
|
||||||
|
log.warning(str(e))
|
||||||
|
continue
|
||||||
qemus.append({"path": qemu_path, "version": version})
|
qemus.append({"path": qemu_path, "version": version})
|
||||||
else:
|
else:
|
||||||
qemu_path = os.path.join(path, f)
|
qemu_path = os.path.join(path, f)
|
||||||
version = await Qemu.get_qemu_version(qemu_path)
|
try:
|
||||||
|
version = await Qemu.get_qemu_version(qemu_path)
|
||||||
|
except QemuError as e:
|
||||||
|
log.warning(str(e))
|
||||||
|
continue
|
||||||
qemus.append({"path": qemu_path, "version": version})
|
qemus.append({"path": qemu_path, "version": version})
|
||||||
|
|
||||||
except OSError:
|
except OSError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -2640,6 +2640,9 @@ class QemuVM(BaseNode):
|
|||||||
command.extend(shlex.split(additional_options))
|
command.extend(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}")
|
||||||
|
# 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'])
|
||||||
return command
|
return command
|
||||||
|
|
||||||
def asdict(self):
|
def asdict(self):
|
||||||
|
@ -152,16 +152,27 @@ class Project:
|
|||||||
|
|
||||||
self._iou_id_lock = asyncio.Lock()
|
self._iou_id_lock = asyncio.Lock()
|
||||||
log.debug(f'Project "{self.name}" [{self._id}] loaded')
|
log.debug(f'Project "{self.name}" [{self._id}] loaded')
|
||||||
|
self.emit_controller_notification("project.created", self.asdict())
|
||||||
|
|
||||||
def emit_notification(self, action, event):
|
def emit_notification(self, action, event):
|
||||||
"""
|
"""
|
||||||
Emit a notification to all clients using this project.
|
Emit a project notification to all clients using this project.
|
||||||
|
|
||||||
:param action: Action name
|
:param action: Action name
|
||||||
:param event: Event to send
|
:param event: Event to send
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.controller.notification.project_emit(action, event, project_id=self.id)
|
self._controller.notification.project_emit(action, event, project_id=self.id)
|
||||||
|
|
||||||
|
def emit_controller_notification(self, action, event):
|
||||||
|
"""
|
||||||
|
Emit a controller notification, all clients will see it.
|
||||||
|
|
||||||
|
:param action: Action name
|
||||||
|
:param event: Event to send
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._controller.notification.controller_emit(action, event)
|
||||||
|
|
||||||
async def update(self, **kwargs):
|
async def update(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -176,7 +187,7 @@ class Project:
|
|||||||
|
|
||||||
# We send notif only if object has changed
|
# We send notif only if object has changed
|
||||||
if old_json != self.asdict():
|
if old_json != self.asdict():
|
||||||
self.emit_notification("project.updated", self.asdict())
|
self.emit_controller_notification("project.updated", self.asdict())
|
||||||
self.dump()
|
self.dump()
|
||||||
|
|
||||||
# update on computes
|
# update on computes
|
||||||
@ -812,7 +823,8 @@ class Project:
|
|||||||
self._clean_pictures()
|
self._clean_pictures()
|
||||||
self._status = "closed"
|
self._status = "closed"
|
||||||
if not ignore_notification:
|
if not ignore_notification:
|
||||||
self.emit_notification("project.closed", self.asdict())
|
self.emit_controller_notification("project.closed", self.asdict())
|
||||||
|
|
||||||
self.reset()
|
self.reset()
|
||||||
self._closing = False
|
self._closing = False
|
||||||
|
|
||||||
@ -868,6 +880,7 @@ class Project:
|
|||||||
shutil.rmtree(self.path)
|
shutil.rmtree(self.path)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise ControllerError(f"Cannot delete project directory {self.path}: {str(e)}")
|
raise ControllerError(f"Cannot delete project directory {self.path}: {str(e)}")
|
||||||
|
self.emit_controller_notification("project.deleted", self.asdict())
|
||||||
|
|
||||||
async def delete_on_computes(self):
|
async def delete_on_computes(self):
|
||||||
"""
|
"""
|
||||||
@ -1001,7 +1014,7 @@ class Project:
|
|||||||
await self.add_drawing(dump=False, **drawing_data)
|
await self.add_drawing(dump=False, **drawing_data)
|
||||||
|
|
||||||
self.dump()
|
self.dump()
|
||||||
# We catch all error to be able to rollback the .gns3 to the previous state
|
# We catch all error to be able to roll back the .gns3 to the previous state
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
for compute in list(self._project_created_on_compute):
|
for compute in list(self._project_created_on_compute):
|
||||||
try:
|
try:
|
||||||
@ -1026,6 +1039,7 @@ class Project:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
self._loading = False
|
self._loading = False
|
||||||
|
self.emit_controller_notification("project.opened", self.asdict())
|
||||||
# Should we start the nodes when project is open
|
# Should we start the nodes when project is open
|
||||||
if self._auto_start:
|
if self._auto_start:
|
||||||
# Start all in the background without waiting for completion
|
# Start all in the background without waiting for completion
|
||||||
|
1
gns3server/static/web-ui/main.054d2e56a89c0b6f1b49.js
Normal file
1
gns3server/static/web-ui/main.054d2e56a89c0b6f1b49.js
Normal file
File diff suppressed because one or more lines are too long
1
gns3server/static/web-ui/runtime.ecefb4ce510d1c218e7d.js
Normal file
1
gns3server/static/web-ui/runtime.ecefb4ce510d1c218e7d.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
!function(){"use strict";var e,v={},g={};function n(e){var a=g[e];if(void 0!==a)return a.exports;var t=g[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,n),t.loaded=!0,t.exports}n.m=v,e=[],n.O=function(a,t,u,o){if(!t){var r=1/0;for(i=0;i<e.length;i++){t=e[i][0],u=e[i][1],o=e[i][2];for(var l=!0,f=0;f<t.length;f++)(!1&o||r>=o)&&Object.keys(n.O).every(function(b){return n.O[b](t[f])})?t.splice(f--,1):(l=!1,o<r&&(r=o));if(l){e.splice(i--,1);var s=u();void 0!==s&&(a=s)}}return a}o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,u,o]},n.n=function(e){var a=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(a,{a:a}),a},n.d=function(e,a){for(var t in a)n.o(a,t)&&!n.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},n.f={},n.e=function(e){return Promise.all(Object.keys(n.f).reduce(function(a,t){return n.f[t](e,a),a},[]))},n.u=function(e){return e+".49028ab13de5de406c90.js"},n.miniCssF=function(e){return"styles.f8555f2eecf8cf87f666.css"},n.hmd=function(e){return(e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:function(){throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e},n.o=function(e,a){return Object.prototype.hasOwnProperty.call(e,a)},function(){var e={},a="gns3-web-ui:";n.l=function(t,u,o,i){if(e[t])e[t].push(u);else{var r,l;if(void 0!==o)for(var f=document.getElementsByTagName("script"),s=0;s<f.length;s++){var c=f[s];if(c.getAttribute("src")==t||c.getAttribute("data-webpack")==a+o){r=c;break}}r||(l=!0,(r=document.createElement("script")).charset="utf-8",r.timeout=120,n.nc&&r.setAttribute("nonce",n.nc),r.setAttribute("data-webpack",a+o),r.src=n.tu(t)),e[t]=[u];var d=function(h,b){r.onerror=r.onload=null,clearTimeout(p);var _=e[t];if(delete e[t],r.parentNode&&r.parentNode.removeChild(r),_&&_.forEach(function(m){return m(b)}),h)return h(b)},p=setTimeout(d.bind(null,void 0,{type:"timeout",target:r}),12e4);r.onerror=d.bind(null,r.onerror),r.onload=d.bind(null,r.onload),l&&document.head.appendChild(r)}}}(),n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},function(){var e;n.tu=function(a){return void 0===e&&(e={createScriptURL:function(t){return t}},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(a)}}(),n.p="",function(){var e={666:0};n.f.j=function(u,o){var i=n.o(e,u)?e[u]:void 0;if(0!==i)if(i)o.push(i[2]);else if(666!=u){var r=new Promise(function(c,d){i=e[u]=[c,d]});o.push(i[2]=r);var l=n.p+n.u(u),f=new Error;n.l(l,function(c){if(n.o(e,u)&&(0!==(i=e[u])&&(e[u]=void 0),i)){var d=c&&("load"===c.type?"missing":c.type),p=c&&c.target&&c.target.src;f.message="Loading chunk "+u+" failed.\n("+d+": "+p+")",f.name="ChunkLoadError",f.type=d,f.request=p,i[1](f)}},"chunk-"+u,u)}else e[u]=0},n.O.j=function(u){return 0===e[u]};var a=function(u,o){var f,s,i=o[0],r=o[1],l=o[2],c=0;for(f in r)n.o(r,f)&&(n.m[f]=r[f]);if(l)var d=l(n);for(u&&u(o);c<i.length;c++)n.o(e,s=i[c])&&e[s]&&e[s][0](),e[i[c]]=0;return n.O(d)},t=self.webpackChunkgns3_web_ui=self.webpackChunkgns3_web_ui||[];t.forEach(a.bind(null,0)),t.push=a.bind(null,t.push.bind(t))}()}();
|
@ -188,7 +188,12 @@ class AsyncioTelnetServer:
|
|||||||
sock = network_writer.get_extra_info("socket")
|
sock = network_writer.get_extra_info("socket")
|
||||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||||
# log.debug("New connection from {}".format(sock.getpeername()))
|
# 60 sec keep alives, close tcp session after 4 missed
|
||||||
|
# Will keep a firewall from aging out telnet console.
|
||||||
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60)
|
||||||
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 10)
|
||||||
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 4)
|
||||||
|
#log.debug("New connection from {}".format(sock.getpeername()))
|
||||||
|
|
||||||
# Keep track of connected clients
|
# Keep track of connected clients
|
||||||
connection = self._connection_factory(network_reader, network_writer, self._window_size_changed_callback)
|
connection = self._connection_factory(network_reader, network_writer, self._window_size_changed_callback)
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
build:
|
version: 2
|
||||||
image: latest
|
|
||||||
|
|
||||||
python:
|
build:
|
||||||
version: 3.6
|
os: "ubuntu-22.04"
|
||||||
|
tools:
|
||||||
|
python: "3.12"
|
||||||
|
|
||||||
|
sphinx:
|
||||||
|
configuration: docs/conf.py
|
||||||
|
@ -6,9 +6,9 @@ aiohttp==3.9.1
|
|||||||
async-timeout==4.0.3
|
async-timeout==4.0.3
|
||||||
aiofiles==23.2.1
|
aiofiles==23.2.1
|
||||||
Jinja2>=3.1.2,<3.2
|
Jinja2>=3.1.2,<3.2
|
||||||
sentry-sdk==1.37.1,<1.38
|
sentry-sdk==1.39.2,<1.40
|
||||||
psutil==5.9.6
|
psutil==5.9.8
|
||||||
distro>=1.8.0
|
distro>=1.9.0
|
||||||
py-cpuinfo==9.0.0
|
py-cpuinfo==9.0.0
|
||||||
sqlalchemy==2.0.23
|
sqlalchemy==2.0.23
|
||||||
aiosqlite==0.19.0
|
aiosqlite==0.19.0
|
||||||
|
@ -163,9 +163,9 @@ log "Install GNS3 packages"
|
|||||||
apt-get install -y gns3-server
|
apt-get install -y gns3-server
|
||||||
|
|
||||||
log "Create user GNS3 with /opt/gns3 as home directory"
|
log "Create user GNS3 with /opt/gns3 as home directory"
|
||||||
if [ ! -d "/opt/gns3/" ]
|
if [ ! -d "/opt/gns3" ]
|
||||||
then
|
then
|
||||||
useradd -m -d /opt/gns3/ gns3
|
useradd -m -d /opt/gns3 gns3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
@ -304,6 +304,11 @@ log "GNS3 installed with success"
|
|||||||
|
|
||||||
if [ $WELCOME_SETUP == 1 ]
|
if [ $WELCOME_SETUP == 1 ]
|
||||||
then
|
then
|
||||||
|
cat <<EOFI > /etc/sudoers.d/gns3
|
||||||
|
gns3 ALL = (ALL) NOPASSWD: /usr/bin/apt-key
|
||||||
|
gns3 ALL = (ALL) NOPASSWD: /usr/bin/apt-get
|
||||||
|
gns3 ALL = (ALL) NOPASSWD: /usr/sbin/reboot
|
||||||
|
EOFI
|
||||||
NEEDRESTART_MODE=a apt-get install -y net-tools
|
NEEDRESTART_MODE=a apt-get install -y net-tools
|
||||||
NEEDRESTART_MODE=a apt-get install -y python3-pip
|
NEEDRESTART_MODE=a apt-get install -y python3-pip
|
||||||
NEEDRESTART_MODE=a apt-get install -y dialog
|
NEEDRESTART_MODE=a apt-get install -y dialog
|
||||||
@ -462,4 +467,4 @@ NEEDRESTART_MODE=a apt-get upgrade
|
|||||||
python3 -c 'import sys; sys.path.append("/usr/local/bin/"); import welcome; ws = welcome.Welcome_dialog(); ws.repair_remote_install()'
|
python3 -c 'import sys; sys.path.append("/usr/local/bin/"); import welcome; ws = welcome.Welcome_dialog(); ws.repair_remote_install()'
|
||||||
cd /opt/gns3
|
cd /opt/gns3
|
||||||
su gns3
|
su gns3
|
||||||
fi
|
fi
|
||||||
|
@ -163,19 +163,38 @@ class Welcome_dialog:
|
|||||||
|
|
||||||
def update(self, force=False):
|
def update(self, force=False):
|
||||||
if not force:
|
if not force:
|
||||||
if self.display.yesno("PLEASE SNAPSHOT THE VM BEFORE RUNNING THE UPGRADE IN CASE OF FAILURE. The server will reboot at the end of the upgrade process. Continue?") != self.display.OK:
|
if self.display.yesno("It is recommended to ensure all Nodes are shutdown before upgrading. Continue?") != self.display.OK:
|
||||||
return
|
return
|
||||||
release = self.get_release()
|
code, option = self.display.menu("Select an option",
|
||||||
if release == "2.2":
|
choices=[("Upgrade GNS3", "Upgrades only the GNS3 pakage and dependences."),
|
||||||
if self.display.yesno("It is recommended to run GNS3 version 2.2 with lastest GNS3 VM based on Ubuntu 18.04 LTS, please download this VM from our website or continue at your own risk!") != self.display.OK:
|
("Upgrade All", "Upgrades all avaiable packages"),
|
||||||
|
("Dist Upgrade", "Upgrades all avaiable packages and the Linux Kernel. Requires a reboot.")])
|
||||||
|
if code == Dialog.OK:
|
||||||
|
if option == "Upgrade GNS3":
|
||||||
|
ret = os.system(
|
||||||
|
"sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A2E3EF7B \
|
||||||
|
&& sudo apt-get update \
|
||||||
|
&& sudo apt-get install -y --only-upgrade gns3-server"
|
||||||
|
)
|
||||||
|
elif option == "Upgrade All":
|
||||||
|
ret = os.system(
|
||||||
|
'sudo apt-key adv --refresh-keys --keyserver keyserver.ubuntu.com \
|
||||||
|
&& sudo apt-get update \
|
||||||
|
&& sudo apt-get upgrade --yes --force-yes -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold"'
|
||||||
|
)
|
||||||
|
elif option == "Dist Upgrade":
|
||||||
|
ret = os.system(
|
||||||
|
'sudo apt-key adv --refresh-keys --keyserver keyserver.ubuntu.com \
|
||||||
|
&& sudo apt-get update \
|
||||||
|
&& sudo apt-get dist-upgrade --yes --force-yes -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold"'
|
||||||
|
)
|
||||||
|
if ret != 0:
|
||||||
|
print("ERROR DURING UPGRADE PROCESS PLEASE TAKE A SCREENSHOT IF YOU NEED SUPPORT")
|
||||||
|
time.sleep(15)
|
||||||
return
|
return
|
||||||
if release.endswith("dev"):
|
if option == "Dist Upgrade":
|
||||||
ret = os.system("curl -Lk https://raw.githubusercontent.com/GNS3/gns3-vm/unstable/scripts/update_{}.sh > /tmp/update.sh && bash -x /tmp/update.sh".format(release))
|
if self.display.yesno("Reboot now?") == self.display.OK:
|
||||||
else:
|
os.system("sudo reboot now")
|
||||||
ret = os.system("curl -Lk https://raw.githubusercontent.com/GNS3/gns3-vm/master/scripts/update_{}.sh > /tmp/update.sh && bash -x /tmp/update.sh".format(release))
|
|
||||||
if ret != 0:
|
|
||||||
print("ERROR DURING UPGRADE PROCESS PLEASE TAKE A SCREENSHOT IF YOU NEED SUPPORT")
|
|
||||||
time.sleep(15)
|
|
||||||
|
|
||||||
|
|
||||||
def migrate(self):
|
def migrate(self):
|
||||||
@ -438,7 +457,8 @@ Images and projects are located in /opt/gns3
|
|||||||
self.display.clear()
|
self.display.clear()
|
||||||
if code == Dialog.OK:
|
if code == Dialog.OK:
|
||||||
if tag == "Shell":
|
if tag == "Shell":
|
||||||
os.execvp("bash", ['/bin/bash'])
|
print("Type: 'welcome.py' to get back to the dialog menu.")
|
||||||
|
sys.exit(0)
|
||||||
elif tag == "Version":
|
elif tag == "Version":
|
||||||
self.mode()
|
self.mode()
|
||||||
elif tag == "Restore":
|
elif tag == "Restore":
|
||||||
|
@ -224,7 +224,9 @@ async def test_compute_httpQuery_project(compute):
|
|||||||
response = MagicMock()
|
response = MagicMock()
|
||||||
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
|
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
|
||||||
response.status = 200
|
response.status = 200
|
||||||
project = Project(name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification') as mock_notification:
|
||||||
|
project = Project(name="Test")
|
||||||
|
mock_notification.assert_called()
|
||||||
await compute.post("/projects", project)
|
await compute.post("/projects", project)
|
||||||
mock.assert_called_with("POST", "https://example.com:84/v3/compute/projects", data=json.dumps(project.asdict()), headers={'content-type': 'application/json'}, auth=None, chunked=None, timeout=20)
|
mock.assert_called_with("POST", "https://example.com:84/v3/compute/projects", data=json.dumps(project.asdict()), headers={'content-type': 'application/json'}, auth=None, chunked=None, timeout=20)
|
||||||
await compute.close()
|
await compute.close()
|
||||||
|
@ -47,16 +47,20 @@ async def node(controller, project):
|
|||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_affect_uuid():
|
async def test_affect_uuid():
|
||||||
|
|
||||||
p = Project(name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification') as mock_notification:
|
||||||
assert len(p.id) == 36
|
p = Project(name="Test")
|
||||||
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f', name="Test 2")
|
mock_notification.assert_called()
|
||||||
assert p.id == '00010203-0405-0607-0809-0a0b0c0d0e0f'
|
assert len(p.id) == 36
|
||||||
|
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f', name="Test 2")
|
||||||
|
assert p.id == '00010203-0405-0607-0809-0a0b0c0d0e0f'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_json():
|
async def test_json():
|
||||||
|
|
||||||
p = Project(name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification') as mock_notification:
|
||||||
|
p = Project(name="Test")
|
||||||
|
mock_notification.assert_called()
|
||||||
|
|
||||||
assert p.asdict() == {
|
assert p.asdict() == {
|
||||||
"name": "Test",
|
"name": "Test",
|
||||||
@ -85,11 +89,11 @@ async def test_json():
|
|||||||
async def test_update(controller):
|
async def test_update(controller):
|
||||||
|
|
||||||
project = Project(controller=controller, name="Hello")
|
project = Project(controller=controller, name="Hello")
|
||||||
project.emit_notification = MagicMock()
|
project.emit_controller_notification = MagicMock()
|
||||||
assert project.name == "Hello"
|
assert project.name == "Hello"
|
||||||
await project.update(name="World")
|
await project.update(name="World")
|
||||||
assert project.name == "World"
|
assert project.name == "World"
|
||||||
project.emit_notification.assert_any_call("project.updated", project.asdict())
|
project.emit_controller_notification.assert_any_call("project.updated", project.asdict())
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@ -110,7 +114,9 @@ async def test_path(projects_dir):
|
|||||||
|
|
||||||
directory = projects_dir
|
directory = projects_dir
|
||||||
with patch("gns3server.utils.path.get_default_project_directory", return_value=directory):
|
with patch("gns3server.utils.path.get_default_project_directory", return_value=directory):
|
||||||
p = Project(project_id=str(uuid4()), name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification') as mock_notification:
|
||||||
|
p = Project(project_id=str(uuid4()), name="Test")
|
||||||
|
mock_notification.assert_called()
|
||||||
assert p.path == os.path.join(directory, p.id)
|
assert p.path == os.path.join(directory, p.id)
|
||||||
assert os.path.exists(os.path.join(directory, p.id))
|
assert os.path.exists(os.path.join(directory, p.id))
|
||||||
|
|
||||||
@ -129,25 +135,29 @@ def test_path_exist(tmpdir):
|
|||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_init_path(projects_dir):
|
async def test_init_path(projects_dir):
|
||||||
|
|
||||||
project_id = str(uuid4())
|
with patch('gns3server.controller.project.Project.emit_controller_notification') as mock_notification:
|
||||||
p = Project(project_id=project_id, name="Test")
|
project_id = str(uuid4())
|
||||||
assert p.path == os.path.join(projects_dir, project_id)
|
p = Project(project_id=project_id, name="Test")
|
||||||
|
mock_notification.assert_called()
|
||||||
|
assert p.path == os.path.join(projects_dir, project_id)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_changing_path_with_quote_not_allowed(projects_dir):
|
async def test_changing_path_with_quote_not_allowed(projects_dir):
|
||||||
|
|
||||||
with pytest.raises(ControllerForbiddenError):
|
with pytest.raises(ControllerForbiddenError):
|
||||||
p = Project(project_id=str(uuid4()), name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification'):
|
||||||
p.path = os.path.join(projects_dir, "project\"53")
|
p = Project(project_id=str(uuid4()), name="Test")
|
||||||
|
p.path = os.path.join(projects_dir, "project\"53")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_captures_directory(tmpdir):
|
async def test_captures_directory(tmpdir):
|
||||||
|
|
||||||
p = Project(name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification'):
|
||||||
assert p.captures_directory == str(p.path + os.path.sep + "project-files" + os.path.sep + "captures")
|
p = Project(name="Test")
|
||||||
assert os.path.exists(p.captures_directory)
|
assert p.captures_directory == str(p.path + os.path.sep + "project-files" + os.path.sep + "captures")
|
||||||
|
assert os.path.exists(p.captures_directory)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@ -682,38 +692,41 @@ async def test_dump(projects_dir):
|
|||||||
|
|
||||||
directory = projects_dir
|
directory = projects_dir
|
||||||
with patch("gns3server.utils.path.get_default_project_directory", return_value=directory):
|
with patch("gns3server.utils.path.get_default_project_directory", return_value=directory):
|
||||||
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f', name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification'):
|
||||||
p.dump()
|
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f', name="Test")
|
||||||
with open(os.path.join(directory, p.id, "Test.gns3")) as f:
|
p.dump()
|
||||||
content = f.read()
|
with open(os.path.join(directory, p.id, "Test.gns3")) as f:
|
||||||
assert "00010203-0405-0607-0809-0a0b0c0d0e0f" in content
|
content = f.read()
|
||||||
|
assert "00010203-0405-0607-0809-0a0b0c0d0e0f" in content
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_open_close(controller):
|
async def test_open_close(controller):
|
||||||
|
|
||||||
project = Project(controller=controller, name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification'):
|
||||||
assert project.status == "opened"
|
project = Project(controller=controller, name="Test")
|
||||||
await project.close()
|
assert project.status == "opened"
|
||||||
project.start_all = AsyncioMagicMock()
|
await project.close()
|
||||||
await project.open()
|
project.start_all = AsyncioMagicMock()
|
||||||
assert not project.start_all.called
|
await project.open()
|
||||||
assert project.status == "opened"
|
assert not project.start_all.called
|
||||||
project.emit_notification = MagicMock()
|
assert project.status == "opened"
|
||||||
await project.close()
|
project.emit_controller_notification = MagicMock()
|
||||||
assert project.status == "closed"
|
await project.close()
|
||||||
project.emit_notification.assert_any_call("project.closed", project.asdict())
|
assert project.status == "closed"
|
||||||
|
project.emit_controller_notification.assert_any_call("project.closed", project.asdict())
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_open_auto_start(controller):
|
async def test_open_auto_start(controller):
|
||||||
|
|
||||||
project = Project(controller=controller, name="Test", auto_start=True)
|
with patch('gns3server.controller.project.Project.emit_controller_notification'):
|
||||||
assert project.status == "opened"
|
project = Project(controller=controller, name="Test", auto_start=True)
|
||||||
await project.close()
|
assert project.status == "opened"
|
||||||
project.start_all = AsyncioMagicMock()
|
await project.close()
|
||||||
await project.open()
|
project.start_all = AsyncioMagicMock()
|
||||||
assert project.start_all.called
|
await project.open()
|
||||||
|
assert project.start_all.called
|
||||||
|
|
||||||
|
|
||||||
def test_is_running(project, node):
|
def test_is_running(project, node):
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
import pytest
|
import pytest
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock, patch
|
||||||
from tests.utils import asyncio_patch
|
from tests.utils import asyncio_patch
|
||||||
|
|
||||||
from gns3server.controller.project import Project
|
from gns3server.controller.project import Project
|
||||||
@ -31,35 +31,36 @@ from gns3server.version import __version__
|
|||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_project_to_topology_empty(tmpdir):
|
async def test_project_to_topology_empty(tmpdir):
|
||||||
|
|
||||||
project = Project(name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification'):
|
||||||
topo = project_to_topology(project)
|
project = Project(name="Test")
|
||||||
assert topo == {
|
topo = project_to_topology(project)
|
||||||
"project_id": project.id,
|
assert topo == {
|
||||||
"name": "Test",
|
"project_id": project.id,
|
||||||
"auto_start": False,
|
"name": "Test",
|
||||||
"auto_close": True,
|
"auto_start": False,
|
||||||
"auto_open": False,
|
"auto_close": True,
|
||||||
"scene_width": 2000,
|
"auto_open": False,
|
||||||
"scene_height": 1000,
|
"scene_width": 2000,
|
||||||
"revision": GNS3_FILE_FORMAT_REVISION,
|
"scene_height": 1000,
|
||||||
"zoom": 100,
|
"revision": GNS3_FILE_FORMAT_REVISION,
|
||||||
"show_grid": False,
|
"zoom": 100,
|
||||||
"show_interface_labels": False,
|
"show_grid": False,
|
||||||
"show_layers": False,
|
"show_interface_labels": False,
|
||||||
"snap_to_grid": False,
|
"show_layers": False,
|
||||||
"grid_size": 75,
|
"snap_to_grid": False,
|
||||||
"drawing_grid_size": 25,
|
"grid_size": 75,
|
||||||
"topology": {
|
"drawing_grid_size": 25,
|
||||||
"nodes": [],
|
"topology": {
|
||||||
"links": [],
|
"nodes": [],
|
||||||
"computes": [],
|
"links": [],
|
||||||
"drawings": []
|
"computes": [],
|
||||||
},
|
"drawings": []
|
||||||
"type": "topology",
|
},
|
||||||
"supplier": None,
|
"type": "topology",
|
||||||
"variables": None,
|
"supplier": None,
|
||||||
"version": __version__
|
"variables": None,
|
||||||
}
|
"version": __version__
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
Loading…
Reference in New Issue
Block a user