Compare commits

..
90 Commits
Author SHA1 Message Date
grossmj 8e2992fbc7 Release v2.2.36 2023-01-04 19:46:30 +08:00
grossmj 8986f10506 Install web-ui v2.2.36 2023-01-04 19:05:24 +08:00
grossmj 10f3adcb60 Sync appliance files 2023-01-04 18:28:14 +08:00
grossmj 5459543eb5 Fix issue when detecting Dynamips version (version is not set until after Dynamips has started) 2023-01-04 18:21:17 +08:00
grossmj e15c36f05c Merge remote-tracking branch 'origin/2.2' into 2.2 2023-01-04 15:12:26 +08:00
grossmj da7c7d16e4 Fix starting Dynamips on Windows 2023-01-04 15:12:09 +08:00
Jeremy Grossmann 8d69f7f792 Merge pull request #2157 from GNS3/qemu-tpm-support
Trusted Platform Module (TPM) support for Qemu VMs
2023-01-04 10:55:52 +05:45
grossmj 297ada529c Prevent TPM to run on Windows 2023-01-04 12:57:48 +08:00
grossmj ae200d9add Add Trusted Platform Module (TPM) support for Qemu VMs 2023-01-04 12:13:19 +08:00
Jeremy Grossmann eb1b70456f Merge pull request #2155 from GNS3/fix/2143
Binding address for console
2023-01-04 07:00:33 +05:45
grossmj 9132002b80 Fix typos 2023-01-04 09:08:40 +08:00
grossmj 771a9a5ddb Require Dynamips 0.2.23 and bind Dynamips hypervisor on 127.0.0.1 2023-01-02 15:26:59 +08:00
Jeremy Grossmann 04ba3b6549 Merge pull request #2154 from GNS3/fix/2069
Use a stock BusyBox for the Docker integration
2023-01-01 16:18:37 +05:45
grossmj 8f9800f444 Update README.rst about static busybox 2023-01-01 18:24:42 +08:00
Jeremy Grossmann 90c971ed74 Merge pull request #2152 from GNS3/fix/2151
Install built-in appliance files at the first start of a newer version of the server
2023-01-01 15:40:48 +05:45
grossmj d2ad9dc5e2 Delete the built-in appliance directory before installing updated files 2023-01-01 17:49:00 +08:00
grossmj e5c8ae4bde Use a stock BusyBox for the Docker integration 2023-01-01 17:04:48 +08:00
grossmj 5bccf4841d Overwrite built-in appliance files when starting a more recent version of the server 2023-01-01 15:57:41 +08:00
grossmj b3a6b9173b Fix reset console. Fixes #1619 2022-12-31 09:43:17 +08:00
grossmj 2d6b260188 Revert "Install importlib-resources==1.3 with Python < 3.9"
This reverts commit 343022c63b.
2022-12-30 21:13:59 +08:00
grossmj c814245426 Revert "Change importlib-resources dependency to v1.4.0"
This reverts commit d787f38c21.
2022-12-30 21:13:49 +08:00
grossmj d787f38c21 Change importlib-resources dependency to v1.4.0 2022-12-30 21:09:54 +08:00
grossmj 343022c63b Install importlib-resources==1.3 with Python < 3.9 2022-12-30 21:05:18 +08:00
grossmj 1148dbc48e Fix issue when calling reset_console with running VPCS and Qemu nodes. Ref #1619 2022-12-30 20:54:37 +08:00
grossmj 85679aaa94 Try importlib-resources for Python 3.9 2022-12-30 11:44:29 +08:00
grossmj 5bcc247881 Make gns3server.appliances a package 2022-12-30 11:37:34 +08:00
grossmj b8d595928b Try to fix tests 2022-12-30 10:35:29 +08:00
grossmj 3804249d89 Fix tests 2022-12-30 10:01:43 +08:00
grossmj c56a8ef8f7 Only use importlib_resources for Python < 3.9. Fixes #2147 2022-12-30 09:15:40 +08:00
grossmj 076e85ddb3 Update sentry-sdk dependency 2022-12-28 15:13:26 +08:00
grossmj 2550fb3495 Support when the user field defined in Docker container is an ID. Fixes #2134 2022-12-28 11:05:22 +08:00
grossmj a91ed34f43 Downgrade Ubuntu to 20.04 to fix missing Python 3.6 2022-12-18 14:24:50 +08:00
grossmj 5209009df9 Upgrade dependencies 2022-12-18 14:14:56 +08:00
grossmj 5ba526e175 Development on v2.2.36.dev2 2022-11-11 00:36:47 +08:00
grossmj d17c243b13 Release v2.2.35.1 2022-11-10 22:21:13 +08:00
grossmj 9e4ae6bc24 Sync appliance files 2022-11-10 22:10:21 +08:00
grossmj 4b410cfa42 Merge branch 'master' into 2.2 2022-11-10 22:06:09 +08:00
grossmj b9e415b6fe Push missing file for Web-Ui v2.2.35 2022-11-10 13:09:10 +08:00
grossmj d2d327cc76 Re-release Web-Ui v2.2.35 2022-11-10 12:38:33 +08:00
grossmj 0a046e43d7 Development on 2.2.36.dev1 2022-11-09 20:02:20 +08:00
grossmj a7036d14d5 Merge branch '2.2' 2022-11-09 20:00:48 +08:00
grossmj 1aca7dbe04 Release v2.2.35 2022-11-08 23:40:25 +08:00
grossmj 338128ca3e Upgrade pywin32 to v305 2022-11-08 23:39:10 +08:00
grossmj e165cc48e3 Use Visual Studio 2022 in appveyor.yml 2022-11-08 23:09:23 +08:00
grossmj c80a55b18c Install appliances and configs without importlib_resources for Windows only 2022-11-08 23:07:45 +08:00
grossmj 284a4b62fb Fix copying appliances and configs when app is frozen 2022-11-08 22:50:59 +08:00
grossmj d33fefa183 Merge branch 'master' into 2.2 2022-11-08 19:29:39 +08:00
grossmj dfb48c884b Release web-ui v2.2.35 2022-11-08 19:29:21 +08:00
grossmj 18ba60d1a3 Downgrade psutil to v5.9.2 2022-11-08 19:18:07 +08:00
grossmj 521132726e Upgrade psutil to v5.9.4 2022-11-08 18:49:31 +08:00
grossmj f80aca7633 Sync appliance files 2022-11-08 18:40:27 +08:00
grossmj 84914ecfa4 Add debug messages to fix VMnet interface list refresh. Ref https://github.com/GNS3/gns3-gui/issues/3381 2022-11-08 12:54:47 +08:00
grossmj 5696d1ccb7 Fix issues with VMnet interface on macOS >= 11.0. Ref #3381 2022-11-07 23:59:33 +08:00
grossmj 18b0863ba8 Merge remote-tracking branch 'origin/2.2' into 2.2
# Conflicts:
#	requirements.txt
2022-11-07 21:50:59 +08:00
grossmj ece47dc279 Upgrade dependencies 2022-11-07 21:48:45 +08:00
Jeremy Grossmann 6e1d49d8ca Merge pull request #2133 from GNS3/use-importlib-resources
Migrate to importlib_resources
2022-11-07 21:24:35 +08:00
grossmj 2e550d839e Fix tests 2022-11-07 20:33:02 +08:00
grossmj a4b24eaceb Use importlib_resources instead of pkg_resources and install built-in appliances in config dir. 2022-11-07 20:12:03 +08:00
grossmj f04702d607 Fix console vnc don't use configured ports in some case. Fixes #2111 2022-11-06 19:36:31 +08:00
grossmj 6f11df6189 Add missing VMware settings in gns3_server.conf 2022-11-06 19:30:24 +08:00
grossmj 9cf2e4f5a6 Make version PEP 440 compliant 2022-11-06 17:51:31 +08:00
Jeremy Grossmann 9316876f97 Merge pull request #2123 from blueneekone/patch-1
Update gns3.service.systemd
2022-11-04 23:01:57 +08:00
grossmj f3b8f43689 Fix creating asyncio task in Python 3.6 2022-10-30 22:21:28 +08:00
grossmj 2d74d1ad94 Fix tests for Python 3.11 2022-10-30 22:07:44 +08:00
grossmj ec50cc7c0d Support for Python 3.11 2022-10-30 19:04:54 +08:00
grossmj f8ee3b3d50 Upgrade pywin32 to v304 2022-10-19 18:31:17 +08:00
Jeremy Grossmann 67e42f9353 Merge pull request #2128 from GNS3/fix/3393
Update requirements.txt
2022-10-18 22:31:56 +08:00
Jeremy Grossmann 31a490211b Merge branch '2.2' into fix/3393 2022-10-18 22:31:04 +08:00
grossmj c7df8331ed Upgrade to Visual Studio 2022 in appveyor.yml 2022-10-18 21:47:10 +08:00
grossmj de1654a50f Upgrade pip and setuptools in appveyor.yml 2022-10-18 21:40:08 +08:00
grossmj a6959de1f8 Upgrade pytest. Fixes #2130 2022-10-18 21:14:53 +08:00
grossmj 8cfedce468 Use jsonschema v3.2.0 for Python 3.6 2022-10-12 22:13:34 +08:00
grossmj 77dd772314 Allow for more dependency versions at patch level 2022-10-12 22:07:37 +08:00
grossmj 9ff302592c Upgrade to aiohttp 3.8.3 2022-10-12 21:40:23 +08:00
grossmj 6b3d4feab8 Replace deprecated distro.linux_distribution() call 2022-10-11 23:28:11 +08:00
grossmj 78b2b93540 Update dev-requirements.txt 2022-10-11 23:23:15 +08:00
grossmj 0303e21059 Update requirements.txt 2022-10-11 23:01:24 +08:00
grossmj e20d1adb0e Downgrade aiohttp to v3.8.1 2022-10-10 16:30:28 +08:00
grossmj e5bee8ff52 Downgrade Jinja2 to support Python 3.6 2022-10-10 15:52:36 +08:00
grossmj 58471ea7f4 Downgrade aiofiles to support Python 3.6 2022-10-10 15:50:35 +08:00
grossmj 9fb0ba5a71 Upgrade dependencies 2022-10-10 14:29:04 +08:00
Evan Waechtler 3d738e83f5 Update gns3.service.systemd
In reference to bug #1918, the gns3.service.systemd file references ExecPath /usr/bin/gns3server which needs to be changed to /usr/local/bin/gns3server for the daemon/service to run without failure.

Please see the change I made to the service above.
2022-10-02 23:25:58 -06:00
grossmj 40c22e389e Merge branch 'master' into 2.2 2022-09-29 14:56:35 +02:00
Jeremy Grossmann 0419c081fe Merge pull request #2083 from a60814billy/fix/binding-on-wrong-interface-in-windows
fix: binding to wrong interface in windows
2022-09-28 17:36:31 +02:00
grossmj dced70a565 Merge branch 'master' into 2.2 2022-09-27 11:55:53 +02:00
grossmj 0d0a06799d Development on 2.2.35dev1 2022-08-29 11:14:44 +02:00
grossmj eeae27ae0d Merge branch '2.2' 2022-08-29 11:11:29 +02:00
Jeremy Grossmann 3634cc8307 Merge pull request #2094 from mm1ke/master
gns3.service.openrc: make openrc script posix compliant
2022-08-08 19:29:30 +02:00
Michael Mair-Keimberger 3b108563a0 gns3.service.openrc: make openrc script posix compliant 2022-08-08 19:23:29 +02:00
BoHong Li 790bf4521d fix: use exact match to find interface in windows to avoid get wrong interface 2022-07-06 14:22:11 +08:00
60 changed files with 877 additions and 154 deletions

No files matched your search

+2 -2
View File
@@ -13,10 +13,10 @@ on:
jobs:
build:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04 # Downgrade Ubuntu to 20.04 to fix missing Python 3.6
strategy:
matrix:
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
steps:
- uses: actions/checkout@v2
+31
View File
@@ -1,5 +1,36 @@
# Change Log
## 2.2.36 04/01/2023
* Install web-ui v2.2.36
* Add Trusted Platform Module (TPM) support for Qemu VMs
* Require Dynamips 0.2.23 and bind Dynamips hypervisor on 127.0.0.1
* Delete the built-in appliance directory before installing updated files
* Use a stock BusyBox for the Docker integration
* Overwrite built-in appliance files when starting a more recent version of the server
* Fix reset console. Fixes #1619
* Only use importlib_resources for Python <= 3.9. Fixes #2147
* Support when the user field defined in Docker container is an ID. Fixes #2134
## 2.2.35.1 10/11/2022
* Re-release Web-Ui v2.2.35
## 2.2.35 08/11/2022
* Release web-ui v2.2.35
* Fix issues with VMnet interface on macOS >= 11.0. Ref #3381
* Use importlib_resources instead of pkg_resources and install built-in appliances in config dir.
* Fix console vnc don't use configured ports in some case. Fixes #2111
* Add missing VMware settings in gns3_server.conf
* Make version PEP 440 compliant
* Support for Python 3.11
* Allow for more dependency versions at patch level
* Replace deprecated distro.linux_distribution() call
* Update gns3.service.systemd
* gns3.service.openrc: make openrc script posix compliant
* fix: use exact match to find interface in windows to avoid get wrong interface
## 2.2.34 28/08/2022
* Use original $PATH in init.sh for Docker containers. Ref #2069
+5
View File
@@ -29,6 +29,11 @@ In addition of Python dependencies listed in a section below, other software may
* mtools is recommended to support data transfer to/from QEMU VMs using virtual disks.
* i386-libraries of libc and libcrypto are optional (Linux only), they are only needed to run IOU based nodes.
Docker support
**************
Docker support needs the script program (`bsdutils` or `util-linux` package), when running a docker VM and a static busybox during installation (python3 setup.py install / pip3 install / package creation).
Branches
--------
+2 -1
View File
@@ -1,6 +1,6 @@
version: '{build}-{branch}'
image: Visual Studio 2015
image: Visual Studio 2022
platform: x64
@@ -12,6 +12,7 @@ environment:
install:
- cinst nmap
- "%PYTHON%\\python.exe -m pip install -U pip setuptools" # upgrade pip & setuptools first
- "%PYTHON%\\python.exe -m pip install -r dev-requirements.txt"
- "%PYTHON%\\python.exe -m pip install -r win-requirements.txt"
+6
View File
@@ -90,3 +90,9 @@ require_kvm = True
enable_hardware_acceleration = True
; Require hardware acceleration in order to start VMs (all platforms)
require_hardware_acceleration = False
[VMware]
; First vmnet interface of the range that can be managed by the GNS3 server
vmnet_start_range = 2
; Last vmnet interface of the range that can be managed by the GNS3 server. It must be maximum 19 on Windows.
vmnet_end_range = 255
+3 -3
View File
@@ -1,8 +1,8 @@
-rrequirements.txt
pytest==7.0.1; python_version < '3.7' # last version to support Python 3.6
pytest==7.1.2; python_version >= '3.7'
pytest==7.2.0; python_version >= '3.7'
pytest==7.0.1; python_version < '3.7' # v7.0.1 is the last version to support Python 3.6
flake8==5.0.4
pytest-timeout==2.1.0
pytest-aiohttp==0.3.0; python_version < '3.7' # last version to support Python 3.6
pytest-aiohttp==1.0.4; python_version >= '3.7'
pytest-aiohttp==0.3.0; python_version < '3.7' # last version to support Python 3.6
@@ -0,0 +1,45 @@
{
"appliance_id": "3da5c614-772c-4963-af86-f24e058c9216",
"name": "Alpine Linux Virt",
"category": "guest",
"description": "Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox.\n\nThis is the qemu version of Alpine Linux, stripped down to the maximum, only the default packages are installed without an SSH server.",
"vendor_name": "Alpine Linux Development Team",
"vendor_url": "http://alpinelinux.org",
"documentation_url": "http://wiki.alpinelinux.org",
"product_name": "Alpine Linux Virt",
"registry_version": 4,
"status": "stable",
"availability": "free",
"maintainer": "Adnan RIHAN",
"maintainer_email": "adnan@rihan.fr",
"usage": "Autologin is enabled as \"root\" with no password.\n\nThe network interfaces aren't configured, you can do either of the following:\n- Use alpine's DHCP client: `udhcpc`\n- Configure them manually (ip address add …, ip route add …)\n- Modify interfaces file in /etc/network/interfaces\n- Use alpine's wizard: `setup-interfaces`",
"symbol": "alpine-virt-qemu.svg",
"port_name_format": "eth{0}",
"qemu": {
"adapter_type": "virtio-net-pci",
"adapters": 1,
"ram": 128,
"hda_disk_interface": "virtio",
"arch": "x86_64",
"console_type": "telnet",
"kvm": "allow"
},
"images": [
{
"filename": "alpine-virt-3.16.img",
"version": "3.16",
"md5sum": "ce90ff64b8f8e5860c49ea4a038e54cc",
"filesize": 96468992,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/alpine-virt-3.16.img/download"
}
],
"versions": [
{
"name": "3.16",
"images": {
"hda_disk_image": "alpine-virt-3.16.img"
}
}
]
}
@@ -30,6 +30,13 @@
"process_priority": "normal"
},
"images": [
{
"filename": "arubaoscx-disk-image-genericx86-p4-20220815162137.vmdk",
"version": "10.10.1000",
"md5sum": "40f9ddf1e12640376af443b5d982f2f6",
"filesize": 356162560,
"download_url": "https://asp.arubanetworks.com/"
},
{
"filename": "arubaoscx-disk-image-genericx86-p4-20220616193419.vmdk",
"version": "10.10.0002",
@@ -95,6 +102,12 @@
}
],
"versions": [
{
"name": "10.10.1000",
"images": {
"hda_disk_image": "arubaoscx-disk-image-genericx86-p4-20220815162137.vmdk"
}
},
{
"name": "10.10.0002",
"images": {
+2 -2
View File
@@ -21,14 +21,14 @@
"images": [
{
"filename": "c3725-adventerprisek9-mz.124-15.T14.image",
"version": "124-25.T14",
"version": "124-15.T14",
"md5sum": "64f8c427ed48fd21bd02cf1ff254c4eb",
"filesize": 97859480
}
],
"versions": [
{
"name": "124-25.T14",
"name": "124-15.T14",
"idlepc": "0x60c09aa0",
"images": {
"image": "c3725-adventerprisek9-mz.124-15.T14.image"
+13
View File
@@ -77,6 +77,13 @@
"md5sum": "4cf5b7fd68075b6f7ee0dd41a4029ca0",
"filesize": 2150017536,
"download_url": "https://software.cisco.com/download/"
},
{
"filename": "Cisco_Firepower_Management_Center_Virtual-6.2.2-81.qcow2",
"version": "6.2.2 (81)",
"md5sum": "2f75c9c6c18a6fbb5516f6f451aef3a4",
"filesize": 2112356352,
"download_url": "https://software.cisco.com/download/"
}
],
"versions": [
@@ -121,6 +128,12 @@
"images": {
"hda_disk_image": "Cisco_Firepower_Management_Center_Virtual_VMware-6.2.1-342-disk1.vmdk"
}
},
{
"name": "6.2.2 (81)",
"images": {
"hda_disk_image": "Cisco_Firepower_Management_Center_Virtual-6.2.2-81.qcow2"
}
}
]
}
+14
View File
@@ -25,6 +25,14 @@
"kvm": "require"
},
"images": [
{
"filename": "cumulus-linux-5.3.1-vx-amd64-qemu.qcow2",
"version": "5.3.1",
"md5sum": "366b4e5afbfb638244fac4dd6cd092fd",
"filesize": 2147479552,
"download_url": "https://www.nvidia.com/en-us/networking/ethernet-switching/cumulus-vx/download/",
"direct_download_url": "https://d2cd9e7ca6hntp.cloudfront.net/public/CumulusLinux-5.3.1/cumulus-linux-5.3.1-vx-amd64-qemu.qcow2"
},
{
"filename": "cumulus-linux-5.1.0-vx-amd64-qemu.qcow2",
"version": "5.1.0",
@@ -239,6 +247,12 @@
}
],
"versions": [
{
"name": "5.3.1",
"images": {
"hda_disk_image": "cumulus-linux-5.3.1-vx-amd64-qemu.qcow2"
}
},
{
"name": "5.1.0",
"images": {
+14 -14
View File
@@ -24,20 +24,20 @@
},
"images": [
{
"filename": "debian-11-genericcloud-amd64-20220711-1073.qcow2",
"version": "11.4",
"md5sum": "e8fadf4bbf7324a2e2875a5ba00588e7",
"filesize": 253231104,
"filename": "debian-11-genericcloud-amd64-20221219-1234.qcow2",
"version": "11.6",
"md5sum": "bd6ddbccc89e40deb7716b812958238d",
"filesize": 258801664,
"download_url": "https://cloud.debian.org/images/cloud/bullseye/",
"direct_download_url": "https://cloud.debian.org/images/cloud/bullseye/20220711-1073/debian-11-genericcloud-amd64-20220711-1073.qcow2"
"direct_download_url": "https://cloud.debian.org/images/cloud/bullseye/20221219-1234/debian-11-genericcloud-amd64-20221219-1234.qcow2"
},
{
"filename": "debian-10-genericcloud-amd64-20220328-962.qcow2",
"version": "10.12",
"md5sum": "e92dfa1fc779fff807856f6ea6876e42",
"filesize": 232980480,
"filename": "debian-10-genericcloud-amd64-20220911-1135.qcow2",
"version": "10.13",
"md5sum": "9d4d1175bef974caba79dd6ca33d500c",
"filesize": 234749952,
"download_url": "https://cloud.debian.org/images/cloud/buster/",
"direct_download_url": "https://cloud.debian.org/images/cloud/buster/20220328-962/debian-10-genericcloud-amd64-20220328-962.qcow2"
"direct_download_url": "https://cloud.debian.org/images/cloud/buster/20220911-1135/debian-10-genericcloud-amd64-20220911-1135.qcow2"
},
{
"filename": "debian-cloud-init-data.iso",
@@ -49,16 +49,16 @@
],
"versions": [
{
"name": "11.4",
"name": "11.6",
"images": {
"hda_disk_image": "debian-11-genericcloud-amd64-20220711-1073.qcow2",
"hda_disk_image": "debian-11-genericcloud-amd64-20221219-1234.qcow2",
"cdrom_image": "debian-cloud-init-data.iso"
}
},
{
"name": "10.12",
"name": "10.13",
"images": {
"hda_disk_image": "debian-10-genericcloud-amd64-20220328-962.qcow2",
"hda_disk_image": "debian-10-genericcloud-amd64-20220911-1135.qcow2",
"cdrom_image": "debian-cloud-init-data.iso"
}
}
+1 -1
View File
@@ -10,7 +10,7 @@
"status": "stable",
"maintainer": "Andras Dosztal",
"maintainer_email": "developers@gns3.net",
"usage": "You can add records by adding entries to the /etc/hosts file in the following format:\n%IP_ADDRESS% %HOSTNAME%.lab %HOSTNAME%\n\nExample:\n192.168.123.10 router1.lab router1",
"usage": "You can add records by adding entries to the /etc/hosts file in the following format:\n%IP_ADDRESS% %HOSTNAME%.lab %HOSTNAME%\n\nExample:\n192.168.123.10 router1.lab router1\n\nIf you require DNS requests to be serviced from a different subnet than the one that the DNS server resides on then do the following:\n\n1. Edit (nano or vim) /ect/init.d/dnsmasq\n2. Find the line DNSMASQ_OPTS=\"$DNSMASQ_OPTS --local-service\"\n3. Remove the --local-service or comment that line out and add DNSMASQ_OPTS=\"\"\n4. Restart dnsmasq - service dnsmaq restart",
"symbol": "linux_guest.svg",
"docker": {
"adapters": 1,
@@ -27,6 +27,13 @@
"options": "-nographic"
},
"images": [
{
"filename": "VOSSGNS3.8.8.0.0.qcow2",
"version": "v8.8.0.0",
"md5sum": "caa01094bad8ea5750261924b82ca746",
"filesize": 348389376,
"direct_download_url": "https://akamai-ep.extremenetworks.com/Extreme_P/github-en/Virtual_VOSS/VOSSGNS3.8.8.0.0.qcow2"
},
{
"filename": "VOSSGNS3.8.4.0.0.qcow2",
"version": "v8.4.0.0",
@@ -78,6 +85,13 @@
}
],
"versions": [
{
"name": "v8.8.0.0",
"images":
{
"hda_disk_image": "VOSSGNS3.8.8.0.0.qcow2"
}
},
{
"name": "v8.4.0.0",
"images": {
+14
View File
@@ -34,6 +34,13 @@
"filesize": 340631552,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAZ_VM64_KVM-v7.0.5-build0365-FORTINET.out.kvm.qcow2",
"version": "7.0.5",
"md5sum": "6cbc1f865ed285bb3a73323e222f03b8",
"filesize": 334184448,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAZ_VM64_KVM-v6-build2288-FORTINET.out.kvm.qcow2",
"version": "6.4.5",
@@ -191,6 +198,13 @@
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.5",
"images": {
"hda_disk_image": "FAZ_VM64_KVM-v7.0.5-build0365-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.5",
"images": {
+42
View File
@@ -27,6 +27,13 @@
"kvm": "allow"
},
"images": [
{
"filename": "FGT_VM64_KVM-v7.2.3.F-build1262-FORTINET.out.kvm.qcow2",
"version": "7.2.3",
"md5sum": "e8f3c5879f0d6fe238dc2665a3508694",
"filesize": 87490560,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v7.2.1.F-build1254-FORTINET.out.kvm.qcow2",
"version": "7.2.1",
@@ -34,6 +41,20 @@
"filesize": 86704128,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v7.0.9.M-build0444-FORTINET.out.kvm.qcow2",
"version": "7.0.9",
"md5sum": "0aee912ab11bf9a4b0e3fc1a62dd0e40",
"filesize": 77135872,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v6.M-build2030-FORTINET.out.kvm.qcow2",
"version": "6.4.11",
"md5sum": "bcd7491ddfa31fec4f618b73792456e4",
"filesize": 69861376,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v6-build1828-FORTINET.out.kvm.qcow2",
"version": "6.4.5",
@@ -261,6 +282,13 @@
}
],
"versions": [
{
"name": "7.2.3",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v7.2.3.F-build1262-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.1",
"images": {
@@ -268,6 +296,20 @@
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.9",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v7.0.9.M-build0444-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.11",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v6.M-build2030-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.5",
"images": {
+14
View File
@@ -34,6 +34,13 @@
"filesize": 242814976,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.0.5-build0365-FORTINET.out.kvm.qcow2",
"version": "7.0.5",
"md5sum": "e8b9c992784cea766b52a427a5fe0279",
"filesize": 237535232,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6-build2288-FORTINET.out.kvm.qcow2",
"version": "6.4.5",
@@ -191,6 +198,13 @@
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.5",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.0.5-build0365-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.5",
"images": {
+14
View File
@@ -22,6 +22,14 @@
"kvm": "allow"
},
"images": [
{
"filename": "frr-8.2.2.qcow2",
"version": "8.2.2",
"md5sum": "45cda6b991a1b9e8205a3a0ecc953640",
"filesize": 56609280,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "http://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/frr-8.2.2.qcow2"
},
{
"filename": "frr-8.1.0.qcow2",
"version": "8.1.0",
@@ -48,6 +56,12 @@
}
],
"versions": [
{
"name": "8.2.2",
"images": {
"hda_disk_image": "frr-8.2.2.qcow2"
}
},
{
"name": "8.1.0",
"images": {
+1 -1
View File
@@ -14,7 +14,7 @@
"usage": "In the web interface login as admin/admin\n\nPersistent configuration:\n- Add \"/var/lib/redis\" as an additional persistent directory.\n- Use \"redis-cli save\" in an auxiliary console to save the configuration.",
"docker": {
"adapters": 1,
"image": "ntop/ntopng:stable",
"image": "ntop/ntopng:latest",
"start_command": "--dns-mode 2 --interface eth0",
"console_type": "http",
"console_http_port": 3000,
+30
View File
@@ -23,6 +23,24 @@
"kvm": "allow"
},
"images": [
{
"filename": "openwrt-22.03.0-x86-64-generic-ext4-combined.img",
"version": "22.03.0",
"md5sum": "0f9a266bd8a6cdfcaf0b59f7ba103a0e",
"filesize": 126353408,
"download_url": "https://downloads.openwrt.org/releases/22.03.0/targets/x86/64/",
"direct_download_url": "https://downloads.openwrt.org/releases/22.03.0/targets/x86/64/openwrt-22.03.0-x86-64-generic-ext4-combined.img.gz",
"compression": "gzip"
},
{
"filename": "openwrt-21.02.3-x86-64-generic-ext4-combined.img",
"version": "21.02.3",
"md5sum": "652c432e758420cb8d749139e8bef14b",
"filesize": 126353408,
"download_url": "https://downloads.openwrt.org/releases/21.02.3/targets/x86/64/",
"direct_download_url": "https://downloads.openwrt.org/releases/21.02.3/targets/x86/64/openwrt-21.02.3-x86-64-generic-ext4-combined.img.gz",
"compression": "gzip"
},
{
"filename": "openwrt-21.02.1-x86-64-generic-ext4-combined.img",
"version": "21.02.1",
@@ -196,6 +214,18 @@
}
],
"versions": [
{
"name": "22.03.0",
"images": {
"hda_disk_image": "openwrt-22.03.0-x86-64-generic-ext4-combined.img"
}
},
{
"name": "21.02.3",
"images": {
"hda_disk_image": "openwrt-21.02.3-x86-64-generic-ext4-combined.img"
}
},
{
"name": "21.02.1",
"images": {
+67
View File
@@ -0,0 +1,67 @@
{
"appliance_id": "c811e588-39ef-41e9-9f60-6e8e08618c3d",
"name": "ReactOS",
"category": "guest",
"description": "Imagine running your favorite Windows applications and drivers in an open-source environment you can trust.\nThat's the mission of ReactOS! ",
"vendor_name": "ReactOS Project",
"vendor_url": "https://reactos.org/",
"documentation_url": "https://reactos.org/what-is-reactos/",
"product_name": "ReactOS",
"product_url": "https://reactos.org/",
"registry_version": 3,
"status": "stable",
"maintainer": "Savio D'souza",
"maintainer_email": "savio2002@yahoo.co.in",
"usage": "Passwords are set during installation.",
"qemu": {
"adapter_type": "e1000",
"adapters": 1,
"ram": 1024,
"hda_disk_interface": "ide",
"arch": "x86_64",
"console_type": "vnc",
"kvm": "require"
},
"images": [
{
"filename": "ReactOS-0.4.14-release-15-gb6088a6.iso",
"version": "Installer-0.4.14-release-15",
"md5sum": "af4be6b27463446905f155f14232d2b4",
"filesize": 140509184,
"download_url": "https://reactos.org/download",
"direct_download_url": "https://sourceforge.net/projects/reactos/files/ReactOS/0.4.14/ReactOS-0.4.14-release-21-g1302c1b-iso.zip/download"
},
{
"filename": "ReactOS-0.4.14-release-15-gb6088a6-Live.iso",
"version": "Live-0.4.14-release-15",
"md5sum": "73c1a0169a9a3b8a4feb91f4d00f5e97",
"filesize": 267386880,
"download_url": "https://reactos.org/download",
"direct_download_url": "https://sourceforge.net/projects/reactos/files/ReactOS/0.4.14/ReactOS-0.4.14-release-21-g1302c1b-live.zip/download"
},
{
"filename": "empty30G.qcow2",
"version": "1.0",
"md5sum": "3411a599e822f2ac6be560a26405821a",
"filesize": 197120,
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%30disk/",
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty30G.qcow2/download"
}
],
"versions": [
{
"name": "Installer-0.4.14-release-15",
"images": {
"hda_disk_image": "empty30G.qcow2",
"cdrom_image": "ReactOS-0.4.14-release-15-gb6088a6.iso"
}
},
{
"name": "Live-0.4.14-release-15",
"images": {
"hda_disk_image": "empty30G.qcow2",
"cdrom_image": "ReactOS-0.4.14-release-15-gb6088a6-Live.iso"
}
}
]
}
+36 -9
View File
@@ -2,7 +2,7 @@
"appliance_id": "f82b74c4-0f30-456f-a582-63daca528502",
"name": "VyOS",
"category": "router",
"description": "VyOS is a community fork of Vyatta, a Linux-based network operating system that provides software-based network routing, firewall, and VPN functionality. VyOS has a subscription LTS version and a community rolling release. The latest version in this appliance is the monthly snapshot of the rolling release track.",
"description": "VyOS is a community fork of Vyatta, a Linux-based network operating system that provides software-based network routing, firewall, and VPN functionality.",
"vendor_name": "Linux",
"vendor_url": "https://vyos.net/",
"documentation_url": "https://docs.vyos.io/",
@@ -26,6 +26,20 @@
"kvm": "allow"
},
"images": [
{
"filename": "vyos-1.3.2-amd64.iso",
"version": "1.3.2",
"md5sum": "070743faac800f9e5197058a8b6b3ba1",
"filesize": 334495744,
"download_url": "https://support.vyos.io/en/downloads/files/vyos-1-3-2-generic-iso-image"
},
{
"filename": "vyos-1.3.1-S1-amd64.iso",
"version": "1.3.1-S1",
"md5sum": "781f345e8a4ab9eb9e075ce5c87c8817",
"filesize": 351272960,
"download_url": "https://support.vyos.io/en/downloads/files/vyos-1-3-1-s1-generic-iso-image"
},
{
"filename": "vyos-1.3.1-amd64.iso",
"version": "1.3.1",
@@ -41,12 +55,11 @@
"download_url": "https://support.vyos.io/en/downloads/files/vyos-1-3-0-generic-iso-image"
},
{
"filename": "vyos-1.3.0-epa3-amd64.iso",
"version": "1.3.0-epa3",
"md5sum": "1b5de684d8995844e35fa5cec3171811",
"filesize": 331350016,
"download_url": "https://vyos.net/get/snapshots/",
"direct_download_url": "https://s3.amazonaws.com/s3-us.vyos.io/snapshot/vyos-1.3.0-epa3/vyos-1.3.0-epa3-amd64.iso"
"filename": "vyos-1.2.9-amd64.iso",
"version": "1.2.9",
"md5sum": "586be23b6256173e174c82d8f1f699a1",
"filesize": 430964736,
"download_url": "https://support.vyos.io/en/downloads/files/vyos-1-2-9-generic-iso-image"
},
{
"filename": "vyos-1.2.8-amd64.iso",
@@ -80,6 +93,20 @@
}
],
"versions": [
{
"name": "1.3.2",
"images": {
"hda_disk_image": "empty8G.qcow2",
"cdrom_image": "vyos-1.3.2-amd64.iso"
}
},
{
"name": "1.3.1-S1",
"images": {
"hda_disk_image": "empty8G.qcow2",
"cdrom_image": "vyos-1.3.1-S1-amd64.iso"
}
},
{
"name": "1.3.1",
"images": {
@@ -95,10 +122,10 @@
}
},
{
"name": "1.3.0-epa3",
"name": "1.2.9",
"images": {
"hda_disk_image": "empty8G.qcow2",
"cdrom_image": "vyos-1.3.0-epa3-amd64.iso"
"cdrom_image": "vyos-1.2.9-amd64.iso"
}
},
{
@@ -0,0 +1,59 @@
{
"appliance_id": "f3b6a3ac-7be5-4bb0-b204-da3712fb646c",
"name": "Windows-11-Dev-Env",
"category": "guest",
"description": "Windows 11 Developer Environment Virtual Machine.",
"vendor_name": "Microsoft",
"vendor_url": "https://www.microsoft.com",
"documentation_url": "https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/",
"product_name": "Windows 11 Development Environment",
"product_url": "https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/",
"registry_version": 4,
"status": "experimental",
"availability": "free",
"maintainer": "Ean Towne",
"maintainer_email": "eantowne@gmail.com",
"usage": "Uses SPICE not VNC\nHighly recommended to install the SPICE-agent from: https://www.spice-space.org/download/windows/spice-guest-tools/spice-guest-tools-latest.exe to be able to change resolution and increase performance.\nThis is an evaluation virtual machine (90 days) and includes:\n* Window 11 Enterprise (Evaluation)\n* Visual Studio 2022 Community Edition with UWP .NET Desktop, Azure, and Windows App SDK for C# workloads enabled\n* Windows Subsystem for Linux 2 enabled with Ubuntu installed\n* Windows Terminal installed\n* Developer mode enabled",
"symbol": "microsoft.svg",
"first_port_name": "Network Adapter 1",
"port_name_format": "Network Adapter {0}",
"qemu": {
"adapter_type": "e1000",
"adapters": 1,
"ram": 4096,
"cpus": 4,
"hda_disk_interface": "sata",
"arch": "x86_64",
"console_type": "spice",
"boot_priority": "c",
"kvm": "require"
},
"images": [
{
"filename": "WinDev2212Eval-disk1.vmdk",
"version": "2212",
"md5sum": "c79f393a067b92e01a513a118d455ac8",
"filesize": 24620493824,
"download_url": "https://aka.ms/windev_VM_vmware",
"compression": "zip"
},
{
"filename": "OVMF-20160813.fd",
"version": "16.08.13",
"md5sum": "8ff0ef1ec56345db5b6bda1a8630e3c6",
"filesize": 2097152,
"download_url": "",
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/OVMF-20160813.fd.zip/download",
"compression": "zip"
}
],
"versions": [
{
"images": {
"bios_image": "OVMF-20160813.fd",
"hda_disk_image": "WinDev2212Eval-disk1.vmdk"
},
"name": "2212"
}
]
}
+50 -21
View File
@@ -77,6 +77,8 @@ class BaseNode:
self._allocate_aux = allocate_aux
self._wrap_console = wrap_console
self._wrapper_telnet_server = None
self._wrap_console_reader = None
self._wrap_console_writer = None
self._internal_console_port = None
self._custom_adapters = []
self._ubridge_require_privileged_access = False
@@ -338,7 +340,6 @@ class BaseNode:
if self._wrap_console:
self._manager.port_manager.release_tcp_port(self._internal_console_port, self._project)
self._internal_console_port = None
if self._aux:
self._manager.port_manager.release_tcp_port(self._aux, self._project)
self._aux = None
@@ -376,17 +377,29 @@ class BaseNode:
remaining_trial = 60
while True:
try:
(reader, writer) = await asyncio.open_connection(host="127.0.0.1", port=self._internal_console_port)
(self._wrap_console_reader, self._wrap_console_writer) = await asyncio.open_connection(
host="127.0.0.1",
port=self._internal_console_port
)
break
except (OSError, ConnectionRefusedError) as e:
if remaining_trial <= 0:
raise e
await asyncio.sleep(0.1)
remaining_trial -= 1
await AsyncioTelnetServer.write_client_intro(writer, echo=True)
server = AsyncioTelnetServer(reader=reader, writer=writer, binary=True, echo=True)
await AsyncioTelnetServer.write_client_intro(self._wrap_console_writer, echo=True)
server = AsyncioTelnetServer(
reader=self._wrap_console_reader,
writer=self._wrap_console_writer,
binary=True,
echo=True
)
# warning: this will raise OSError exception if there is a problem...
self._wrapper_telnet_server = await asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console)
self._wrapper_telnet_server = await asyncio.start_server(
server.run,
self._manager.port_manager.console_host,
self.console
)
async def stop_wrap_console(self):
"""
@@ -394,12 +407,15 @@ class BaseNode:
"""
if self._wrapper_telnet_server:
self._wrap_console_writer.close()
await self._wrap_console_writer.wait_closed()
self._wrapper_telnet_server.close()
await self._wrapper_telnet_server.wait_closed()
self._wrapper_telnet_server = None
async def reset_console(self):
async def reset_wrap_console(self):
"""
Reset console
Reset the wrap console (restarts the Telnet proxy)
"""
await self.stop_wrap_console()
@@ -578,8 +594,12 @@ class BaseNode:
# no need to allocate a port when the console type is none
self._console = None
elif console_type == "vnc":
# VNC is a special case and the range must be 5900-6000
self._console = self._manager.port_manager.get_free_tcp_port(self._project, 5900, 6000)
vnc_console_start_port_range, vnc_console_end_port_range = self._get_vnc_console_port_range()
self._console = self._manager.port_manager.get_free_tcp_port(
self._project,
vnc_console_start_port_range,
vnc_console_end_port_range
)
else:
self._console = self._manager.port_manager.get_free_tcp_port(self._project)
@@ -778,18 +798,8 @@ class BaseNode:
# on Linux we use RAW sockets by default excepting if host traffic must be blocked
await self._ubridge_send('bridge add_nio_linux_raw {name} "{interface}"'.format(name=bridge_name, interface=ethernet_interface))
elif sys.platform.startswith("win"):
# on Windows we use Winpcap/Npcap
windows_interfaces = interfaces()
npf_id = None
source_mac = None
for interface in windows_interfaces:
# Winpcap/Npcap uses a NPF ID to identify an interface on Windows
if "netcard" in interface and ethernet_interface in interface["netcard"]:
npf_id = interface["id"]
source_mac = interface["mac_address"]
elif ethernet_interface in interface["name"]:
npf_id = interface["id"]
source_mac = interface["mac_address"]
npf_id, source_mac = self._find_windows_interface(ethernet_interface)
if npf_id:
await self._ubridge_send('bridge add_nio_ethernet {name} "{interface}"'.format(name=bridge_name,
interface=npf_id))
@@ -813,6 +823,25 @@ class BaseNode:
await self._ubridge_send('bridge set_pcap_filter {name} "not ether src {mac}"'.format(name=bridge_name, mac=source_mac))
log.info('PCAP filter applied on "{interface}" for source MAC {mac}'.format(interface=ethernet_interface, mac=source_mac))
@staticmethod
def _find_windows_interface(ethernet_interface):
"""
Get NPF ID and MAC address by input ethernet interface name.
Return None, None when not match any interface
:returns: NPF ID and MAC address
"""
# on Windows we use Winpcap/Npcap
windows_interfaces = interfaces()
for interface in windows_interfaces:
if str.strip(ethernet_interface) == str.strip(interface["name"]):
return interface["id"], interface["mac_address"]
for interface in windows_interfaces:
if "netcard" in interface and ethernet_interface in interface["netcard"]:
return interface["id"], interface["mac_address"]
return None, None
def _create_local_udp_tunnel(self):
"""
Creates a local UDP tunnel (pair of 2 NIOs, one for each direction)
+6 -2
View File
@@ -520,10 +520,14 @@ class DockerVM(BaseNode):
# https://github.com/GNS3/gns3-gui/issues/1039
try:
process = await asyncio.subprocess.create_subprocess_exec(
"docker", "exec", "-i", self._cid, "/gns3/bin/busybox", "script", "-qfc", "while true; do TERM=vt100 /gns3/bin/busybox sh; done", "/dev/null",
"script",
"-qfc",
f"docker exec -i -t {self._cid} /gns3/bin/busybox sh -c 'while true; do TERM=vt100 /gns3/bin/busybox sh; done'",
"/dev/null",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,
stdin=asyncio.subprocess.PIPE)
stdin=asyncio.subprocess.PIPE
)
except OSError as e:
raise DockerError("Could not start auxiliary console process: {}".format(e))
server = AsyncioTelnetServer(reader=process.stdout, writer=process.stdin, binary=True, echo=True)
Binary file not shown.
@@ -0,0 +1,15 @@
#!/gns3/bin/busybox sh
SCRIPT="/gns3/etc/udhcpc/default.script"
if [ "$(cat "/proc/$PPID/comm" 2>/dev/null)" = ifup ]; then
# remove "-n" argument
for arg do
shift
[ "$arg" = "-n" ] || set -- "$@" "$arg"
done
# add default parameters
set -- -t 3 -T 2 -A 1 -b "$@"
fi
exec /tmp/gns3/bin/udhcpc -s "$SCRIPT" "$@"
+9 -1
View File
@@ -87,5 +87,13 @@ done
ifup -a -f
# continue normal docker startup
eval HOME=$(echo ~${GNS3_USER-root})
case "$GNS3_USER" in
[1-9][0-9]*)
# for when the user field defined in the Docker container is an ID
export GNS3_USER=$(cat /etc/passwd | grep ${GNS3_USER-root} | awk -F: '{print $1}')
;;
*)
;;
esac
eval HOME="$(echo ~${GNS3_USER-root})"
exec su ${GNS3_USER-root} -p -- /gns3/run-cmd.sh "$OLD_PATH" "$@"
+10 -4
View File
@@ -278,10 +278,14 @@ class Dynamips(BaseManager):
if not working_dir:
working_dir = tempfile.gettempdir()
# FIXME: hypervisor should always listen to 127.0.0.1
# See https://github.com/GNS3/dynamips/issues/62
server_config = self.config.get_section_config("Server")
server_host = server_config.get("host")
if not sys.platform.startswith("win"):
# Hypervisor should always listen to 127.0.0.1
# See https://github.com/GNS3/dynamips/issues/62
# This was fixed in Dynamips v0.2.23 which hasn't been built for Windows
server_host = "127.0.0.1"
else:
server_config = self.config.get_section_config("Server")
server_host = server_config.get("host")
try:
info = socket.getaddrinfo(server_host, 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
@@ -306,6 +310,8 @@ class Dynamips(BaseManager):
await hypervisor.connect()
if parse_version(hypervisor.version) < parse_version('0.2.11'):
raise DynamipsError("Dynamips version must be >= 0.2.11, detected version is {}".format(hypervisor.version))
if not sys.platform.startswith("win") and parse_version(hypervisor.version) < parse_version('0.2.23'):
raise DynamipsError("Dynamips version must be >= 0.2.23 on Linux/macOS, detected version is {}".format(hypervisor.version))
return hypervisor
@@ -94,7 +94,9 @@ class DynamipsHypervisor:
try:
version = await self.send("hypervisor version")
self._version = version[0].split("-", 1)[0]
log.info("Dynamips version {} detected".format(self._version))
except IndexError:
log.warning("Dynamips version could not be detected")
self._version = "Unknown"
# this forces to send the working dir to Dynamips
+3 -5
View File
@@ -204,11 +204,9 @@ class Hypervisor(DynamipsHypervisor):
command = [self._path]
command.extend(["-N1"]) # use instance IDs for filenames
command.extend(["-l", "dynamips_i{}_log.txt".format(self._id)]) # log file
# Dynamips cannot listen for hypervisor commands and for console connections on
# 2 different IP addresses.
# See https://github.com/GNS3/dynamips/issues/62
if self._console_host != "0.0.0.0" and self._console_host != "::":
command.extend(["-H", "{}:{}".format(self._host, self._port)])
if not sys.platform.startswith("win"):
command.extend(["-H", "{}:{}".format(self._host, self._port), "--console-binding-addr", self._console_host])
else:
command.extend(["-H", str(self._port)])
return command
+7 -1
View File
@@ -977,7 +977,6 @@ class Router(BaseNode):
raise DynamipsError('"{name}" must be stopped to change the console type to {console_type}'.format(name=self._name,
console_type=console_type))
self.console_type = console_type
if self._console and console_type == "telnet":
@@ -993,6 +992,13 @@ class Router(BaseNode):
self.aux = aux
await self._hypervisor.send('vm set_aux_tcp_port "{name}" {aux}'.format(name=self._name, aux=aux))
async def reset_console(self):
"""
Reset console
"""
pass # reset console is not supported with Dynamips
async def get_cpu_usage(self, cpu_id=0):
"""
Shows cpu usage in seconds, "cpu_id" is ignored.
+8 -1
View File
@@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import socket
import ipaddress
from aiohttp.web import HTTPConflict
from gns3server.config import Config
@@ -83,7 +84,7 @@ class PortManager:
@console_host.setter
def console_host(self, new_host):
"""
Bind console host to 0.0.0.0 if remote connections are allowed.
Bind console host to 0.0.0.0 or :: if remote connections are allowed.
"""
server_config = Config.instance().get_section_config("Server")
@@ -91,6 +92,12 @@ class PortManager:
if remote_console_connections:
log.warning("Remote console connections are allowed")
self._console_host = "0.0.0.0"
try:
ip = ipaddress.ip_address(new_host)
if isinstance(ip, ipaddress.IPv6Address):
self._console_host = "::"
except ValueError:
log.warning("Could not determine IP address type for console host")
else:
self._console_host = new_host
+99 -8
View File
@@ -78,6 +78,7 @@ class QemuVM(BaseNode):
self._monitor_host = server_config.get("monitor_host", "127.0.0.1")
self._process = None
self._cpulimit_process = None
self._swtpm_process = None
self._monitor = None
self._stdout_file = ""
self._qemu_img_stdout_file = ""
@@ -120,6 +121,7 @@ class QemuVM(BaseNode):
self._initrd = ""
self._kernel_image = ""
self._kernel_command_line = ""
self._tpm = False
self._legacy_networking = False
self._replicate_network_connection_state = True
self._create_config_disk = False
@@ -686,7 +688,7 @@ class QemuVM(BaseNode):
"""
Sets whether a config disk is automatically created on HDD disk interface (secondary slave)
:param replicate_network_connection_state: boolean
:param create_config_disk: boolean
"""
if create_config_disk:
@@ -807,6 +809,30 @@ class QemuVM(BaseNode):
log.info('QEMU VM "{name}" [{id}] has set the number of vCPUs to {cpus}'.format(name=self._name, id=self._id, cpus=cpus))
self._cpus = cpus
@property
def tpm(self):
"""
Returns whether TPM is activated for this QEMU VM.
:returns: boolean
"""
return self._tpm
@tpm.setter
def tpm(self, tpm):
"""
Sets whether TPM is activated for this QEMU VM.
:param tpm: boolean
"""
if tpm:
log.info('QEMU VM "{name}" [{id}] has enabled the Trusted Platform Module (TPM)'.format(name=self._name, id=self._id))
else:
log.info('QEMU VM "{name}" [{id}] has disabled the Trusted Platform Module (TPM)'.format(name=self._name, id=self._id))
self._tpm = tpm
@property
def options(self):
"""
@@ -984,11 +1010,8 @@ class QemuVM(BaseNode):
"""
if self._cpulimit_process and self._cpulimit_process.returncode is None:
self._cpulimit_process.kill()
try:
self._process.wait(3)
except subprocess.TimeoutExpired:
log.error("Could not kill cpulimit process {}".format(self._cpulimit_process.pid))
self._cpulimit_process.terminate()
self._cpulimit_process = None
def _set_cpu_throttling(self):
"""
@@ -1003,7 +1026,9 @@ class QemuVM(BaseNode):
cpulimit_exec = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), "cpulimit", "cpulimit.exe")
else:
cpulimit_exec = "cpulimit"
subprocess.Popen([cpulimit_exec, "--lazy", "--pid={}".format(self._process.pid), "--limit={}".format(self._cpu_throttling)], cwd=self.working_dir)
command = [cpulimit_exec, "--lazy", "--pid={}".format(self._process.pid), "--limit={}".format(self._cpu_throttling)]
self._cpulimit_process = subprocess.Popen(command, cwd=self.working_dir)
log.info("CPU throttled to {}%".format(self._cpu_throttling))
except FileNotFoundError:
raise QemuError("cpulimit could not be found, please install it or deactivate CPU throttling")
@@ -1079,7 +1104,8 @@ class QemuVM(BaseNode):
await self._set_process_priority()
if self._cpu_throttling:
self._set_cpu_throttling()
if self._tpm:
self._start_swtpm()
if "-enable-kvm" in command_string or "-enable-hax" in command_string:
self._hw_virtualization = True
@@ -1162,6 +1188,7 @@ class QemuVM(BaseNode):
log.warning('QEMU VM "{}" PID={} is still running'.format(self._name, self._process.pid))
self._process = None
self._stop_cpulimit()
self._stop_swtpm()
if self.on_close != "save_vm_state":
await self._clear_save_vm_stated()
await self._export_config()
@@ -1567,6 +1594,14 @@ class QemuVM(BaseNode):
self._process = None
return False
async def reset_console(self):
"""
Reset console
"""
if self.is_running():
await self.reset_wrap_console()
def command(self):
"""
Returns the QEMU command line.
@@ -1987,6 +2022,60 @@ class QemuVM(BaseNode):
return options
def _start_swtpm(self):
"""
Start swtpm (TPM emulator)
"""
if sys.platform.startswith("win"):
raise QemuError("swtpm (TPM emulator) is not supported on Windows")
tpm_dir = os.path.join(self.working_dir, "tpm")
os.makedirs(tpm_dir, exist_ok=True)
tpm_sock = os.path.join(self.temporary_directory, "swtpm.sock")
swtpm = shutil.which("swtpm")
if not swtpm:
raise QemuError("Could not find swtpm (TPM emulator)")
try:
command = [
swtpm,
"socket",
"--tpm2",
'--tpmstate', "dir={}".format(tpm_dir),
"--ctrl",
"type=unixio,path={},terminate".format(tpm_sock)
]
command_string = " ".join(shlex_quote(s) for s in command)
log.info("Starting swtpm (TPM emulator) with: {}".format(command_string))
self._swtpm_process = subprocess.Popen(command, cwd=self.working_dir)
log.info("swtpm (TPM emulator) has started")
except (OSError, subprocess.SubprocessError) as e:
raise QemuError("Could not start swtpm (TPM emulator): {}".format(e))
def _stop_swtpm(self):
"""
Stop swtpm (TPM emulator)
"""
if self._swtpm_process and self._swtpm_process.returncode is None:
self._swtpm_process.terminate()
self._swtpm_process = None
def _tpm_options(self):
"""
Return the TPM options for Qemu.
"""
tpm_sock = os.path.join(self.temporary_directory, "swtpm.sock")
options = [
"-chardev",
"socket,id=chrtpm,path={}".format(tpm_sock),
"-tpmdev",
"emulator,id=tpm0,chardev=chrtpm",
"-device",
"tpm-tis,tpmdev=tpm0"
]
return options
async def _network_options(self):
network_options = []
@@ -2282,6 +2371,8 @@ class QemuVM(BaseNode):
command.extend((await self._saved_state_option()))
if self._console_type == "telnet":
command.extend((await self._disable_graphics()))
if self._tpm:
command.extend(self._tpm_options())
if additional_options:
try:
command.extend(shlex.split(additional_options))
+4
View File
@@ -360,6 +360,8 @@ class VMware(BaseManager):
def refresh_vmnet_list(self, ubridge=True):
log.debug("Refreshing VMnet list with uBridge={}".format(ubridge))
if ubridge:
# VMnet host adapters must be present when uBridge is used
vmnet_interfaces = self._get_vmnet_interfaces_ubridge()
@@ -368,6 +370,7 @@ class VMware(BaseManager):
self._vmnets_info = vmnet_interfaces.copy()
vmnet_interfaces = list(vmnet_interfaces.keys())
log.debug("Found {} VMnet interfaces".format(len(vmnet_interfaces)))
# remove vmnets already in use
for vmware_vm in self._nodes.values():
for used_vmnet in vmware_vm.vmnets:
@@ -378,6 +381,7 @@ class VMware(BaseManager):
# remove vmnets that are not managed
for vmnet in vmnet_interfaces.copy():
if vmnet in vmnet_interfaces and self.is_managed_vmnet(vmnet) is False:
log.debug("{} is not managed by GNS3".format(vmnet))
vmnet_interfaces.remove(vmnet)
self._vmnets = vmnet_interfaces
+4
View File
@@ -465,6 +465,10 @@ class VMwareVM(BaseNode):
try:
if self._ubridge_hypervisor:
if parse_version(platform.mac_ver()[0]) >= parse_version("11.0.0"):
# give VMware some time to create the bridge interfaces, so they can be found
# by psutil and used by uBridge
await asyncio.sleep(1)
for adapter_number in range(0, self._adapters):
nio = self._ethernet_adapters[adapter_number].get_nio(0)
if nio:
+8
View File
@@ -344,6 +344,14 @@ class VPCSVM(BaseNode):
return True
return False
async def reset_console(self):
"""
Reset console
"""
if self.is_running():
await self.reset_wrap_console()
@BaseNode.console_type.setter
def console_type(self, new_console_type):
"""
+26 -9
View File
@@ -23,7 +23,14 @@ import socket
import shutil
import aiohttp
try:
import importlib_resources
except ImportError:
from importlib import resources as importlib_resources
from ..config import Config
from ..utils import parse_version
from .project import Project
from .template import Template
from .appliance import Appliance
@@ -35,7 +42,6 @@ from .symbols import Symbols
from ..version import __version__
from .topology import load_topology
from .gns3vm import GNS3VM
from ..utils.get_resource import get_resource
from .gns3vm.gns3_vm_error import GNS3VMError
import logging
@@ -65,7 +71,7 @@ class Controller:
async def start(self):
log.info("Controller is starting")
self.load_base_files()
self._install_base_configs()
server_config = Config.instance().get_section_config("Server")
Config.instance().listen_for_config_changes(self._update_config)
host = server_config.get("host", "localhost")
@@ -242,6 +248,9 @@ class Controller:
if "iou_license" in controller_settings:
self._iou_license_settings = controller_settings["iou_license"]
if parse_version(__version__) > parse_version(controller_settings.get("version", "")):
self._appliance_manager.install_builtin_appliances()
self._appliance_manager.appliances_etag = controller_settings.get("appliances_etag")
self._appliance_manager.load_appliances()
self._template_manager.load_templates(controller_settings.get("templates"))
@@ -269,20 +278,28 @@ class Controller:
except OSError as e:
log.error(str(e))
def load_base_files(self):
def _install_base_configs(self):
"""
At startup we copy base file to the user location to allow
them to customize it
"""
dst_path = self.configs_path()
src_path = get_resource('configs')
log.info(f"Installing base configs in '{dst_path}'")
try:
for file in os.listdir(src_path):
if not os.path.exists(os.path.join(dst_path, file)):
shutil.copy(os.path.join(src_path, file), os.path.join(dst_path, file))
except OSError:
pass
if hasattr(sys, "frozen") and sys.platform.startswith("win"):
resource_path = os.path.normpath(os.path.join(os.path.dirname(sys.executable), "configs"))
for filename in os.listdir(resource_path):
if not os.path.exists(os.path.join(dst_path, filename)):
shutil.copy(os.path.join(resource_path, filename), os.path.join(dst_path, filename))
else:
for entry in importlib_resources.files('gns3server.configs').iterdir():
full_path = os.path.join(dst_path, entry.name)
if entry.is_file() and not os.path.exists(full_path):
log.debug(f"Installing base config file {entry.name} to {full_path}")
shutil.copy(str(entry), os.path.join(dst_path, entry.name))
except OSError as e:
log.error(f"Could not install base config files to {dst_path}: {e}")
def images_path(self):
"""
+45 -6
View File
@@ -15,17 +15,23 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
import shutil
import json
import uuid
import asyncio
import aiohttp
import shutil
try:
import importlib_resources
except ImportError:
from importlib import resources as importlib_resources
from .appliance import Appliance
from ..config import Config
from ..utils.asyncio import locking
from ..utils.get_resource import get_resource
import logging
log = logging.getLogger(__name__)
@@ -65,9 +71,9 @@ class ApplianceManager:
return self._appliances
def appliances_path(self):
def _custom_appliances_path(self):
"""
Get the image storage directory
Get the custom appliance storage directory
"""
server_config = Config.instance().get_section_config("Server")
@@ -75,13 +81,46 @@ class ApplianceManager:
os.makedirs(appliances_path, exist_ok=True)
return appliances_path
def _builtin_appliances_path(self, delete_first=False):
"""
Get the built-in appliance storage directory
"""
config = Config.instance()
appliances_dir = os.path.join(config.config_dir, "appliances")
if delete_first:
shutil.rmtree(appliances_dir, ignore_errors=True)
os.makedirs(appliances_dir, exist_ok=True)
return appliances_dir
def install_builtin_appliances(self):
"""
At startup we copy the built-in appliances files.
"""
dst_path = self._builtin_appliances_path(delete_first=True)
log.info(f"Installing built-in appliances in '{dst_path}'")
try:
if hasattr(sys, "frozen") and sys.platform.startswith("win"):
resource_path = os.path.normpath(os.path.join(os.path.dirname(sys.executable), "appliances"))
for filename in os.listdir(resource_path):
shutil.copy(os.path.join(resource_path, filename), os.path.join(dst_path, filename))
else:
for entry in importlib_resources.files('gns3server.appliances').iterdir():
full_path = os.path.join(dst_path, entry.name)
if entry.is_file():
log.debug(f"Installing built-in appliance file {entry.name} to {full_path}")
shutil.copy(str(entry), os.path.join(dst_path, entry.name))
except OSError as e:
log.error(f"Could not install built-in appliance files to {dst_path}: {e}")
def load_appliances(self, symbol_theme="Classic"):
"""
Loads appliance files from disk.
"""
self._appliances = {}
for directory, builtin in ((get_resource('appliances'), True,), (self.appliances_path(), False,)):
for directory, builtin in ((self._builtin_appliances_path(), True,), (self._custom_appliances_path(), False,)):
if directory and os.path.isdir(directory):
for file in os.listdir(directory):
if not file.endswith('.gns3a') and not file.endswith('.gns3appliance'):
@@ -181,7 +220,7 @@ class ApplianceManager:
from . import Controller
Controller.instance().save()
json_data = await response.json()
appliances_dir = get_resource('appliances')
appliances_dir = self._builtin_appliances_path()
downloaded_appliance_files = []
for appliance in json_data:
if appliance["type"] == "file":
+1 -1
View File
@@ -34,7 +34,7 @@ log = logging.getLogger(__name__)
class Node:
# This properties are used only on controller and are not forwarded to the compute
# These properties are used only on controller and are not forwarded to computes
CONTROLLER_ONLY_PROPERTIES = ["x", "y", "z", "locked", "width", "height", "symbol", "label", "console_host",
"port_name_format", "first_port_name", "port_segment_size", "ports",
"category", "console_auto_start"]
+2 -2
View File
@@ -58,7 +58,7 @@ class CrashReport:
Report crash to a third party service
"""
DSN = "https://3f074423e7664595923ae5895b0819c4@o19455.ingest.sentry.io/38482"
DSN = "https://3318fddc3b9f4752b7b00929ac2999e3@o19455.ingest.sentry.io/38482"
_instance = None
def __init__(self):
@@ -93,7 +93,7 @@ class CrashReport:
"os:release": platform.release(),
"os:win_32": " ".join(platform.win32_ver()),
"os:mac": "{} {}".format(platform.mac_ver()[0], platform.mac_ver()[2]),
"os:linux": " ".join(distro.linux_distribution()),
"os:linux": distro.name(pretty=True),
}
+13
View File
@@ -190,6 +190,10 @@ QEMU_CREATE_SCHEMA = {
"description": "Replicate the network connection state for links in Qemu",
"type": ["boolean", "null"],
},
"tpm": {
"description": "Enable the Trusted Platform Module (TPM) in Qemu",
"type": ["boolean", "null"],
},
"create_config_disk": {
"description": "Automatically create a config disk on HDD disk interface (secondary slave)",
"type": ["boolean", "null"],
@@ -384,6 +388,10 @@ QEMU_UPDATE_SCHEMA = {
"description": "Replicate the network connection state for links in Qemu",
"type": ["boolean", "null"],
},
"tpm": {
"description": "Enable the Trusted Platform Module (TPM) in Qemu",
"type": ["boolean", "null"],
},
"create_config_disk": {
"description": "Automatically create a config disk on HDD disk interface (secondary slave)",
"type": ["boolean", "null"],
@@ -591,6 +599,10 @@ QEMU_OBJECT_SCHEMA = {
"description": "Replicate the network connection state for links in Qemu",
"type": "boolean",
},
"tpm": {
"description": "Enable the Trusted Platform Module (TPM) in Qemu",
"type": "boolean",
},
"create_config_disk": {
"description": "Automatically create a config disk on HDD disk interface (secondary slave)",
"type": ["boolean", "null"],
@@ -665,6 +677,7 @@ QEMU_OBJECT_SCHEMA = {
"kernel_command_line",
"legacy_networking",
"replicate_network_connection_state",
"tpm",
"create_config_disk",
"on_close",
"cpu_throttling",
+5
View File
@@ -183,6 +183,11 @@ QEMU_TEMPLATE_PROPERTIES = {
"type": "boolean",
"default": True
},
"tpm": {
"description": "Enable the Trusted Platform Module (TPM) in Qemu",
"type": "boolean",
"default": False
},
"create_config_disk": {
"description": "Automatically create a config disk on HDD disk interface (secondary slave)",
"type": "boolean",
+1 -1
View File
@@ -46,6 +46,6 @@
gtag('config', 'G-5D6FZL9923');
</script>
<script src="runtime.91a209cf21f6fb848205.js" defer></script><script src="polyfills-es5.865074f5cd9a121111a2.js" nomodule defer></script><script src="polyfills.2f91a039d848e57ff02e.js" defer></script><script src="main.61abec15ec5cf18f7c62.js" defer></script>
<script src="runtime.91a209cf21f6fb848205.js" defer></script><script src="polyfills-es5.865074f5cd9a121111a2.js" nomodule defer></script><script src="polyfills.2f91a039d848e57ff02e.js" defer></script><script src="main.022350cecd1e6d733a93.js" defer></script>
</body></html>
@@ -1 +1 @@
(self.webpackChunkgns3_web_ui=self.webpackChunkgns3_web_ui||[]).push([[179],{98255:function(ue){function q(f){return Promise.resolve().then(function(){var U=new Error("Cannot find module '"+f+"'");throw U.code="MODULE_NOT_FOUND",U})}q.keys=function(){return[]},q.resolve=q,q.id=98255,ue.exports=q},82908:function(ue){ue.exports=function(f,U){(null==U||U>f.length)&&(U=f.length);for(var B=0,V=new Array(U);B<U;B++)V[B]=f[B];return V},ue.exports.default=ue.exports,ue.exports.__esModule=!0},36457:function(ue){ue.exports=function(f){if(Array.isArray(f))return f},ue.exports.default=ue.exports,ue.exports.__esModule=!0},35036:function(ue){ue.exports=function(f,U){var B=null==f?null:"undefined"!=typeof Symbol&&f[Symbol.iterator]||f["@@iterator"];if(null!=B){var R,b,V=[],Z=!0,T=!1;try{for(B=B.call(f);!(Z=(R=B.next()).done)&&(V.push(R.value),!U||V.length!==U);Z=!0);}catch(v){T=!0,b=v}finally{try{!Z&&null!=B.return&&B.return()}finally{if(T)throw b}}return V}},ue.exports.default=ue.exports,ue.exports.__esModule=!0},13969:function(ue){ue.exports=function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")},ue.exports.default=ue.exports,ue.exports.__esModule=!0},6326:function(ue,q,f){var U=f(36457),B=f(35036),V=f(54850),Z=f(13969);ue.exports=function(R,b){return U(R)||B(R,b)||V(R,b)||Z()},ue.exports.default=ue.exports,ue.exports.__esModule=!0},54850:function(ue,q,f){var U=f(82908);ue.exports=function(V,Z){if(V){if("string"==typeof V)return U(V,Z);var T=Object.prototype.toString.call(V).slice(8,-1);if("Object"===T&&V.constructor&&(T=V.constructor.name),"Map"===T||"Set"===T)return Array.from(V);if("Arguments"===T||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(T))return U(V,Z)}},ue.exports.default=ue.exports,ue.exports.__esModule=!0},26552:function(ue,q,f){ue.exports=f(55590)},61855:function(ue,q,f){"use strict";f.d(q,{ZT:function(){return B},mG:function(){return v},Jh:function(){return I},ev:function(){return N}});var U=function($,ae){return(U=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(se,ce){se.__proto__=ce}||function(se,ce){for(var le in ce)Object.prototype.hasOwnProperty.call(ce,le)&&(se[le]=ce[le])})($,ae)};function B($,ae){if("function"!=typeof ae&&null!==ae)throw new TypeError("Class extends value "+String(ae)+" is not a constructor or null");function se(){this.constructor=$}U($,ae),$.prototype=null===ae?Object.create(ae):(se.prototype=ae.prototype,new se)}function v($,ae,se,ce){return new(se||(se=Promise))(function(oe,Ae){function be(_t){try{qe(ce.next(_t))}catch(yt){Ae(yt)}}function it(_t){try{qe(ce.throw(_t))}catch(yt){Ae(yt)}}function qe(_t){_t.done?oe(_t.value):function(oe){return oe instanceof se?oe:new se(function(Ae){Ae(oe)})}(_t.value).then(be,it)}qe((ce=ce.apply($,ae||[])).next())})}function I($,ae){var ce,le,oe,Ae,se={label:0,sent:function(){if(1&oe[0])throw oe[1];return oe[1]},trys:[],ops:[]};return Ae={next:be(0),throw:be(1),return:be(2)},"function"==typeof Symbol&&(Ae[Symbol.iterator]=function(){return this}),Ae;function be(qe){return function(_t){return function(qe){if(ce)throw new TypeError("Generator is already executing.");for(;se;)try{if(ce=1,le&&(oe=2&qe[0]?le.return:qe[0]?le.throw||((oe=le.return)&&oe.call(le),0):le.next)&&!(oe=oe.call(le,qe[1])).done)return oe;switch(le=0,oe&&(qe=[2&qe[0],oe.value]),qe[0]){case 0:case 1:oe=qe;break;case 4:return se.label++,{value:qe[1],done:!1};case 5:se.label++,le=qe[1],qe=[0];continue;case 7:qe=se.ops.pop(),se.trys.pop();continue;default:if(!(oe=(oe=se.trys).length>0&&oe[oe.length-1])&&(6===qe[0]||2===qe[0])){se=0;continue}if(3===qe[0]&&(!oe||qe[1]>oe[0]&&qe[1]<oe[3])){se.label=qe[1];break}if(6===qe[0]&&se.label<oe[1]){se.label=oe[1],oe=qe;break}if(oe&&se.label<oe[2]){se.label=oe[2],se.ops.push(qe);break}oe[2]&&se.ops.pop(),se.trys.pop();continue}qe=ae.call($,se)}catch(_t){qe=[6,_t],le=0}finally{ce=oe=0}if(5&qe[0])throw qe[1];return{value:qe[0]?qe[1]:void 0,done:!0}}([qe,_t])}}}function N($,ae,se){if(se||2===arguments.length)for(var oe,ce=0,le=ae.length;ce<le;ce++)(oe||!(ce in ae))&&(oe||(oe=Array.prototype.slice.call(ae,0,ce)),oe[ce]=ae[ce]);return $.concat(oe||Array.prototype.slice.call(ae))}},739:function(ue,q,f){"use strict";f.d(q,{l3:function(){return T},_j:function(){return V},LC:function(){return Z},ZN:function(){return O},jt:function(){return b},pV:function(){return E},F4:function(){return M},IO:function(){return A},vP:function(){return I},SB:function(){return k},oB:function(){return D},eR:function(){return _},X$:function(){return R},ZE:function(){return F},k1:function(){return z}});var U=f(14105),B=f(18967),V=function K(){(0,B.Z)(this,K)},Z=function K(){(0,B.Z)(this,K)},T="*";function R(K,j){return{type:7,name:K,definitions:j,options:{}}}function b(K){var j=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return{type:4,styles:j,timings:K}}function I(K){var j=arguments.length>1&&void 0!==arguments[1]?arguments[1]Line truncated
(self.webpackChunkgns3_web_ui=self.webpackChunkgns3_web_ui||[]).push([[179],{98255:function(ue){function q(f){return Promise.resolve().then(function(){var U=new Error("Cannot find module '"+f+"'");throw U.code="MODULE_NOT_FOUND",U})}q.keys=function(){return[]},q.resolve=q,q.id=98255,ue.exports=q},82908:function(ue){ue.exports=function(f,U){(null==U||U>f.length)&&(U=f.length);for(var B=0,V=new Array(U);B<U;B++)V[B]=f[B];return V},ue.exports.default=ue.exports,ue.exports.__esModule=!0},36457:function(ue){ue.exports=function(f){if(Array.isArray(f))return f},ue.exports.default=ue.exports,ue.exports.__esModule=!0},35036:function(ue){ue.exports=function(f,U){var B=null==f?null:"undefined"!=typeof Symbol&&f[Symbol.iterator]||f["@@iterator"];if(null!=B){var R,b,V=[],Z=!0,T=!1;try{for(B=B.call(f);!(Z=(R=B.next()).done)&&(V.push(R.value),!U||V.length!==U);Z=!0);}catch(v){T=!0,b=v}finally{try{!Z&&null!=B.return&&B.return()}finally{if(T)throw b}}return V}},ue.exports.default=ue.exports,ue.exports.__esModule=!0},13969:function(ue){ue.exports=function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")},ue.exports.default=ue.exports,ue.exports.__esModule=!0},6326:function(ue,q,f){var U=f(36457),B=f(35036),V=f(54850),Z=f(13969);ue.exports=function(R,b){return U(R)||B(R,b)||V(R,b)||Z()},ue.exports.default=ue.exports,ue.exports.__esModule=!0},54850:function(ue,q,f){var U=f(82908);ue.exports=function(V,Z){if(V){if("string"==typeof V)return U(V,Z);var T=Object.prototype.toString.call(V).slice(8,-1);if("Object"===T&&V.constructor&&(T=V.constructor.name),"Map"===T||"Set"===T)return Array.from(V);if("Arguments"===T||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(T))return U(V,Z)}},ue.exports.default=ue.exports,ue.exports.__esModule=!0},26552:function(ue,q,f){ue.exports=f(55590)},61855:function(ue,q,f){"use strict";f.d(q,{ZT:function(){return B},mG:function(){return v},Jh:function(){return I},ev:function(){return N}});var U=function($,ae){return(U=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(se,ce){se.__proto__=ce}||function(se,ce){for(var le in ce)Object.prototype.hasOwnProperty.call(ce,le)&&(se[le]=ce[le])})($,ae)};function B($,ae){if("function"!=typeof ae&&null!==ae)throw new TypeError("Class extends value "+String(ae)+" is not a constructor or null");function se(){this.constructor=$}U($,ae),$.prototype=null===ae?Object.create(ae):(se.prototype=ae.prototype,new se)}function v($,ae,se,ce){return new(se||(se=Promise))(function(oe,Ae){function be(_t){try{qe(ce.next(_t))}catch(yt){Ae(yt)}}function it(_t){try{qe(ce.throw(_t))}catch(yt){Ae(yt)}}function qe(_t){_t.done?oe(_t.value):function(oe){return oe instanceof se?oe:new se(function(Ae){Ae(oe)})}(_t.value).then(be,it)}qe((ce=ce.apply($,ae||[])).next())})}function I($,ae){var ce,le,oe,Ae,se={label:0,sent:function(){if(1&oe[0])throw oe[1];return oe[1]},trys:[],ops:[]};return Ae={next:be(0),throw:be(1),return:be(2)},"function"==typeof Symbol&&(Ae[Symbol.iterator]=function(){return this}),Ae;function be(qe){return function(_t){return function(qe){if(ce)throw new TypeError("Generator is already executing.");for(;se;)try{if(ce=1,le&&(oe=2&qe[0]?le.return:qe[0]?le.throw||((oe=le.return)&&oe.call(le),0):le.next)&&!(oe=oe.call(le,qe[1])).done)return oe;switch(le=0,oe&&(qe=[2&qe[0],oe.value]),qe[0]){case 0:case 1:oe=qe;break;case 4:return se.label++,{value:qe[1],done:!1};case 5:se.label++,le=qe[1],qe=[0];continue;case 7:qe=se.ops.pop(),se.trys.pop();continue;default:if(!(oe=(oe=se.trys).length>0&&oe[oe.length-1])&&(6===qe[0]||2===qe[0])){se=0;continue}if(3===qe[0]&&(!oe||qe[1]>oe[0]&&qe[1]<oe[3])){se.label=qe[1];break}if(6===qe[0]&&se.label<oe[1]){se.label=oe[1],oe=qe;break}if(oe&&se.label<oe[2]){se.label=oe[2],se.ops.push(qe);break}oe[2]&&se.ops.pop(),se.trys.pop();continue}qe=ae.call($,se)}catch(_t){qe=[6,_t],le=0}finally{ce=oe=0}if(5&qe[0])throw qe[1];return{value:qe[0]?qe[1]:void 0,done:!0}}([qe,_t])}}}function N($,ae,se){if(se||2===arguments.length)for(var oe,ce=0,le=ae.length;ce<le;ce++)(oe||!(ce in ae))&&(oe||(oe=Array.prototype.slice.call(ae,0,ce)),oe[ce]=ae[ce]);return $.concat(oe||Array.prototype.slice.call(ae))}},739:function(ue,q,f){"use strict";f.d(q,{l3:function(){return T},_j:function(){return V},LC:function(){return Z},ZN:function(){return O},jt:function(){return b},pV:function(){return E},F4:function(){return M},IO:function(){return A},vP:function(){return I},SB:function(){return k},oB:function(){return D},eR:function(){return _},X$:function(){return R},ZE:function(){return F},k1:function(){return z}});var U=f(14105),B=f(18967),V=function K(){(0,B.Z)(this,K)},Z=function K(){(0,B.Z)(this,K)},T="*";function R(K,j){return{type:7,name:K,definitions:j,options:{}}}function b(K){var j=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return{type:4,styles:j,timings:K}}function I(K){var j=arguments.length>1&&void 0!==arguments[1]?arguments[1]Line truncated
+1
View File
@@ -82,6 +82,7 @@ async def subprocess_check_output(*args, cwd=None, env=None, stderr=False):
# and the code of VPCS, dynamips... Will detect it's not the correct binary
return output.decode("utf-8", errors="ignore")
async def wait_for_process_termination(process, timeout=10):
"""
Wait for a process terminate, and raise asyncio.TimeoutError in case of
+6 -1
View File
@@ -15,6 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import asyncio
@@ -39,7 +40,11 @@ class Pool():
while len(self._tasks) > 0 or len(pending) > 0:
while len(self._tasks) > 0 and len(pending) < self._concurrency:
task, args, kwargs = self._tasks.pop(0)
pending.add(task(*args, **kwargs))
if sys.version_info >= (3, 7):
t = asyncio.create_task(task(*args, **kwargs))
else:
t = asyncio.get_event_loop().create_task(task(*args, **kwargs))
pending.add(t)
(done, pending) = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)
for task in done:
if task.exception():
@@ -202,6 +202,7 @@ class AsyncioTelnetServer:
except ConnectionError:
async with self._lock:
network_writer.close()
await network_writer.wait_closed()
if self._reader_process == network_reader:
self._reader_process = None
# Cancel current read from this reader
@@ -216,6 +217,8 @@ class AsyncioTelnetServer:
try:
writer.write_eof()
await writer.drain()
writer.close()
await writer.wait_closed()
except (AttributeError, ConnectionError):
continue
+13 -21
View File
@@ -15,32 +15,22 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import tempfile
import pkg_resources
import atexit
import logging
import os
import sys
log = logging.getLogger(__name__)
try:
egg_cache_dir = tempfile.mkdtemp()
pkg_resources.set_extraction_path(egg_cache_dir)
except ValueError:
# If the path is already set the module throw an error
pass
import importlib_resources
except ImportError:
from importlib import resources as importlib_resources
@atexit.register
def clean_egg_cache():
try:
import shutil
log.debug("Clean egg cache %s", egg_cache_dir)
shutil.rmtree(egg_cache_dir)
except Exception:
# We don't care if we can not cleanup
pass
from contextlib import ExitStack
resource_manager = ExitStack()
atexit.register(resource_manager.close)
log = logging.getLogger(__name__)
def get_resource(resource_name):
@@ -51,7 +41,9 @@ def get_resource(resource_name):
resource_path = None
if hasattr(sys, "frozen"):
resource_path = os.path.normpath(os.path.join(os.path.dirname(sys.executable), resource_name))
elif not hasattr(sys, "frozen") and pkg_resources.resource_exists("gns3server", resource_name):
resource_path = pkg_resources.resource_filename("gns3server", resource_name)
resource_path = os.path.normpath(resource_path)
else:
ref = importlib_resources.files("gns3server") / resource_name
path = resource_manager.enter_context(importlib_resources.as_file(ref))
if os.path.exists(path):
resource_path = os.path.normpath(path)
return resource_path
+4 -4
View File
@@ -23,15 +23,15 @@
# or negative for a release candidate or beta (after the base version
# number has been incremented)
__version__ = "2.2.34"
__version_info__ = (2, 2, 34, 0)
__version__ = "2.2.36"
__version_info__ = (2, 2, 36, 0)
if "dev" in __version__:
try:
import os
import subprocess
if os.path.exists(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", ".git")):
r = subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]).decode().strip()
__version__ = "{}-{}".format(__version__, r)
r = subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]).decode().strip("\n")
__version__ += "+" + r
except Exception as e:
print(e)
+8 -4
View File
@@ -164,8 +164,6 @@ class Route(object):
"description": kw.get("description", ""),
})
func = asyncio.coroutine(func)
async def control_schema(request):
# This block is executed at each method call
server_config = Config.instance().get_section_config("Server")
@@ -181,7 +179,10 @@ class Route(object):
response = Response(request=request, route=route, output_schema=output_schema)
request = await parse_request(request, None, raw)
await func(request, response)
if asyncio.iscoroutinefunction(func):
await func(request, response)
else:
func(request, response)
return response
# API call
@@ -195,7 +196,10 @@ class Route(object):
except OSError as e:
log.warning("Could not write to the record file {}: {}".format(record_file, e))
response = Response(request=request, route=route, output_schema=output_schema)
await func(request, response)
if asyncio.iscoroutinefunction(func):
await func(request, response)
else:
func(request, response)
except aiohttp.web.HTTPBadRequest as e:
response = Response(request=request, route=route)
response.set_status(e.status)
+2 -2
View File
@@ -23,8 +23,8 @@ depend() {
checkconfig() {
if yesno "${GNS3_SERVER_LOG_ENABLED}" ; then
command_args+=" --log ${GNS3_SERVER_LOG}";
if [ "${command_user}" ] ; then
command_args="${command_args} --log ${GNS3_SERVER_LOG}";
if [ "${command_user}" ] ; then
checkpath --directory --mode 0700 --owner "${command_user}" "${GNS3_SERVER_LOG_PATH}";
else
unset command_user
+2 -2
View File
@@ -6,7 +6,7 @@ After=network.target network-online.target
[Service]
User=gns3
Group=gns3
ExecStart=/usr/bin/gns3server
ExecStart=/usr/local/bin/gns3server
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target
+16 -12
View File
@@ -1,12 +1,16 @@
jsonschema==3.2.0
aiohttp==3.8.1
aiohttp-cors==0.7.0
aiofiles==0.8.0
Jinja2==3.0.3
sentry-sdk==1.9.5
psutil==5.9.1
async-timeout==4.0.2
distro==1.7.0
py-cpuinfo==8.0.0
setuptools==60.6.0; python_version >= '3.7' # don't upgrade because of https://github.com/pypa/setuptools/issues/3084
setuptools==59.6.0; python_version < '3.7' # v59.7.0 dropped support for Python 3.6
jsonschema>=4.17.3,<4.18; python_version >= '3.7'
jsonschema==3.2.0; python_version < '3.7' # v3.2.0 is the last version to support Python 3.6
aiohttp>=3.8.3,<3.9
aiohttp-cors>=0.7.0,<0.8
aiofiles>=22.1.0,<22.2; python_version >= '3.7'
aiofiles==0.8.0; python_version < '3.7' # v0.8.0 is the last version to support Python 3.6
Jinja2>=3.1.2,<3.2; python_version >= '3.7'
Jinja2==3.0.3; python_version < '3.7' # v3.0.3 is the last version to support Python 3.6
sentry-sdk==1.12.1,<1.13
psutil==5.9.4
async-timeout>=4.0.2,<4.1
distro>=1.7.0
py-cpuinfo>=9.0.0,<10.0
importlib-resources>=1.3; python_version <= '3.9'
setuptools>=60.8.1; python_version >= '3.7'
setuptools==59.6.0; python_version < '3.7' # v59.6.0 is the last version to support Python 3.6
+27
View File
@@ -16,6 +16,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
import shutil
import subprocess
from setuptools import setup, find_packages
from setuptools.command.test import test as TestCommand
@@ -39,6 +43,28 @@ class PyTest(TestCommand):
sys.exit(errcode)
BUSYBOX_PATH = "gns3server/compute/docker/resources/bin/busybox"
def copy_busybox():
if not sys.platform.startswith("linux"):
return
if os.path.isfile(BUSYBOX_PATH):
return
for bb_cmd in ("busybox-static", "busybox.static", "busybox"):
bb_path = shutil.which(bb_cmd)
if bb_path:
if subprocess.call(["ldd", bb_path],
stdin=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL):
shutil.copy2(bb_path, BUSYBOX_PATH, follow_symlinks=True)
break
else:
raise SystemExit("No static busybox found")
copy_busybox()
dependencies = open("requirements.txt", "r").read().splitlines()
setup(
@@ -81,6 +107,7 @@ setup(
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: Implementation :: CPython",
],
)
+9 -1
View File
@@ -1343,7 +1343,15 @@ async def test_start_aux(vm):
with asyncio_patch("asyncio.subprocess.create_subprocess_exec", return_value=MagicMock()) as mock_exec:
await vm._start_aux()
mock_exec.assert_called_with('docker', 'exec', '-i', 'e90e34656842', '/gns3/bin/busybox', 'script', '-qfc', 'while true; do TERM=vt100 /gns3/bin/busybox sh; done', '/dev/null', stderr=asyncio.subprocess.STDOUT, stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE)
mock_exec.assert_called_with(
"script",
"-qfc",
"docker exec -i -t e90e34656842 /gns3/bin/busybox sh -c 'while true; do TERM=vt100 /gns3/bin/busybox sh; done'",
"/dev/null",
stderr=asyncio.subprocess.STDOUT,
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE
)
async def test_create_network_interfaces(vm):
+12 -1
View File
@@ -173,7 +173,7 @@ async def test_termination_callback(vm):
await vm._termination_callback(0)
assert vm.status == "stopped"
await queue.get(1) #  Ping
await queue.get(1) # Ping
(action, event, kwargs) = await queue.get(1)
assert action == "node.updated"
@@ -401,6 +401,17 @@ async def test_spice_option(vm, fake_qemu_img_binary):
assert '-vga qxl' in ' '.join(options)
async def test_tpm_option(vm, tmpdir, fake_qemu_img_binary):
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
vm._tpm = True
tpm_sock = os.path.join(vm.temporary_directory, "swtpm.sock")
options = await vm._build_command()
assert '-chardev socket,id=chrtpm,path={}'.format(tpm_sock) in ' '.join(options)
assert '-tpmdev emulator,id=tpm0,chardev=chrtpm' in ' '.join(options)
assert '-device tpm-tis,tpmdev=tpm0' in ' '.join(options)
async def test_disk_options_multiple_disk(vm, tmpdir, fake_qemu_img_binary):
vm._hda_disk_image = str(tmpdir / "test0.qcow2")
+4 -3
View File
@@ -381,16 +381,16 @@ async def test_get_free_project_name(controller):
assert controller.get_free_project_name("Hello") == "Hello"
async def test_load_base_files(controller, config, tmpdir):
async def test_install_base_configs(controller, config, tmpdir):
config.set_section_config("Server", {"configs_path": str(tmpdir)})
with open(str(tmpdir / 'iou_l2_base_startup-config.txt'), 'w+') as f:
f.write('test')
controller.load_base_files()
controller._install_base_configs()
assert os.path.exists(str(tmpdir / 'iou_l3_base_startup-config.txt'))
# Check is the file has not been overwrite
# Check is the file has not been overwritten
with open(str(tmpdir / 'iou_l2_base_startup-config.txt')) as f:
assert f.read() == 'test'
@@ -410,6 +410,7 @@ def test_appliances(controller, tmpdir):
with open(str(tmpdir / "my_appliance2.gns3a"), 'w+') as f:
json.dump(my_appliance, f)
controller.appliance_manager.install_builtin_appliances()
with patch("gns3server.config.Config.get_section_config", return_value={"appliances_path": str(tmpdir)}):
controller.appliance_manager.load_appliances()
assert len(controller.appliance_manager.appliances) > 0
+8 -6
View File
@@ -185,12 +185,14 @@ async def test_qemu_update(compute_api, vm, free_console_port, fake_qemu_vm):
"hdb_disk_image": "linux载.img"
}
response = await compute_api.put("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert response.json["name"] == "test"
assert response.json["console"] == free_console_port
assert response.json["hdb_disk_image"] == "linux载.img"
assert response.json["ram"] == 1024
with patch("gns3server.compute.qemu.qemu_vm.QemuVM.updated") as mock:
response = await compute_api.put("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert response.json["name"] == "test"
assert response.json["console"] == free_console_port
assert response.json["hdb_disk_image"] == "linux载.img"
assert response.json["ram"] == 1024
assert mock.called
async def test_qemu_nio_create_udp(compute_api, vm):
+1 -1
View File
@@ -1,4 +1,4 @@
-rrequirements.txt
pywin32==303
pywin32==305
wmi==1.5.1