Compare commits

...
136 Commits
Author SHA1 Message Date
grossmj e8a7e80456 Release v2.2.46 2024-02-26 16:55:12 +08:00
grossmj ab05784c33 Sync appliances 2024-02-26 16:45:37 +08:00
grossmj 6983e686ca Bundle web-ui v2.2.46 2024-02-26 16:42:46 +08:00
grossmj 3631202ce5 Merge remote-tracking branch 'origin/2.2' into 2.2 2024-02-26 16:36:21 +08:00
grossmj 8d8a3247c4 Bundle web-ui v2.2.46 2024-02-26 16:35:47 +08:00
Jeremy Grossmann d100a132d6 Merge pull request #2360 from GNS3/bugfix/3555
Fix export project
2024-02-26 16:27:39 +08:00
Jeremy Grossmann 52638a9a8d Merge branch '2.2' into bugfix/3555 2024-02-26 16:22:15 +08:00
grossmj 9a5af82a28 Save empty directories when exporting a project 2024-02-24 19:02:16 +08:00
Jeremy Grossmann 14a618766d Merge pull request #2359 from GNS3/bugfix/2357
Fix Docker VM hasn't access to all resources
2024-02-22 19:37:55 +08:00
grossmj 0137688ba7 Test busybox is installed 2024-02-22 13:05:48 +08:00
grossmj 84db3b9996 Fix not all Docker resources are copied to a writable location 2024-02-22 12:59:44 +08:00
Jeremy Grossmann 0a08031d85 Merge pull request #2355 from GNS3/refactor/busybox
Install Docker resources in writable location
2024-02-14 16:18:25 +08:00
grossmj 1a53c9aabf Backport from v3: install Docker resources in a writable location at runtime. 2024-02-14 16:13:45 +08:00
grossmj 1f5085608c Use Docker API v1.24 to get version. 2024-02-14 15:40:19 +08:00
Jeremy Grossmann 16f72b4d3d Merge pull request #2347 from SpikefishSolutions/DeadTelnetConsoleFix
Address the telnet console death bug.
2024-02-09 20:33:16 +11:00
grossmj 3ced41633f Upgrade dependencies 2024-02-09 17:07:35 +11:00
Jeremy Grossmann 4fa10be5aa Merge pull request #2353 from GNS3/feature/drop-python-3.6
Drop Python 3.6 support
2024-02-09 17:01:40 +11:00
grossmj f050fc7e00 Change runtime checks for Python version 2024-02-09 16:49:58 +11:00
grossmj c93aafc9af Fix aiohttp dependency for Python 3.7 2024-02-09 16:45:46 +11:00
grossmj 93520b4d6c Do not test with Python 3.6 2024-02-09 16:34:44 +11:00
grossmj 1fb0260ae6 Drop support for Python 3.6 2024-02-09 16:28:23 +11:00
John Fleming 763ef24108 Address the telnet console bug. Add wait_for for drain() call. If we're stuck on drain then the buffer isn't getting emptied. 5 seconds after drain() blocks, exception will be thrown and client will be removed from connection table and will no longer be a problem. 2024-02-02 22:09:31 -05:00
grossmj 17aabd6cda Merge branch 'master' into 2.2 2024-01-28 20:04:19 +11:00
grossmj d94adf4c8f Merge remote-tracking branch 'origin/master' 2024-01-28 19:56:40 +11:00
Jeremy Grossmann 4dd9cf2da2 Merge pull request #2340 from spikefishjohn/patch-3
Update telnet_server.py
2024-01-28 19:56:26 +11:00
grossmj e2a3d391d8 Merge remote-tracking branch 'origin/2.2' into 2.2 2024-01-28 12:14:28 +11:00
John Fleming 6c5f54fe57 Update telnet_server.py
Maybe use the correct object name this time for the socket objects.
2024-01-28 12:14:07 +11:00
John Fleming 082fbee1bd Update telnet_server.py
Set tcp keepalive timers to 60 seconds. Seems to default to 2 hours on ubuntu 22. Most firewalls will age out an idle tcp session at 1 hour.

Will not address telnet console failing after a tcp session has failed (TimeoutError).
2024-01-28 12:14:07 +11:00
Xatrekak 6d97feaced Fixed updating system and GNS3. 2024-01-28 12:14:01 +11:00
Dustin 8d35089661 Update welcome.py
Fixed an issue where the shell option in dialog failed to drop you back to bash.
2024-01-28 12:13:55 +11:00
Dustin 6455f62447 Update remote-install.sh
Removed an extra slash at the end when setting the user home directory. This was causing unexpected behavior for other scrips as ~ was aliased to /opt/gns3/ instead of the expected  /opt/gns3.

This caused an extra / to appear in commands unexpectedly.
2024-01-28 12:13:55 +11:00
grossmj 2fb3b1ebab Use Python 3.8 to publish API doc 2024-01-28 12:13:46 +11:00
grossmj 58399a9fa8 Upgrade sentry-sdk, psutil and distro dependencies 2024-01-28 12:13:12 +11:00
grossmj 907b305ecf Development on 2.2.46.dev1 2024-01-28 12:13:12 +11:00
grossmj 57f92db124 Release v2.2.45 2024-01-28 12:13:12 +11:00
grossmj 0f6f943a83 Bundle web-ui v2.2.45 2024-01-28 12:13:12 +11:00
grossmj 2cb76b2274 Remove old web-ui files 2024-01-28 12:13:11 +11:00
grossmj 2d2db52a8b Bundle web-ui v2.2.45 2024-01-28 12:13:11 +11:00
grossmj a8d0818e07 Sync appliances 2024-01-28 12:13:11 +11:00
grossmj f7eb2492d9 Fix mouse offset issues with VNC in Qemu. Fixes #2335 2024-01-28 12:13:11 +11:00
grossmj 218522b08c Fix issues when generating docs 2024-01-28 12:13:10 +11:00
grossmj 470f13f448 Update readthedocs.yml to use Python 3.12 2024-01-28 12:13:10 +11:00
grossmj 317aa669ac Update readthedocs.yml 2024-01-28 12:13:10 +11:00
grossmj 8d160ad5ed Update documentation 2024-01-28 12:13:10 +11:00
grossmj e3493870b2 Add project.created, project.opened and project.deleted controller notification stream.
Move project.updated and project.closed from project notification to controller notification stream.
2024-01-28 12:13:09 +11:00
grossmj d466c85385 Do not stop searching for Qemu binaries if one binary cannot be executed. Ref #2306 2024-01-28 12:13:09 +11:00
grossmj 35d4391fc0 Fix Ethernet switch and Ethernet hub port validations. Fixes #2334 2024-01-28 12:13:09 +11:00
grossmj eea0ab69bd Bundle dev version of the web-ui 2024-01-28 12:13:09 +11:00
grossmj 22ade94118 Update CORS policy 2024-01-28 12:13:08 +11:00
grossmj 08ee40548f Add custom executable paths on Windows 2024-01-28 12:13:08 +11:00
grossmj 7f05a06766 Upgrade sentry-sdk and aiohttp 2024-01-28 12:13:08 +11:00
grossmj 9fd2f58ef7 Development in 2.2.45.dev3 2024-01-28 12:13:08 +11:00
grossmj b9b802ebab Release v2.2.44.1 2024-01-28 12:13:08 +11:00
grossmj 1d86e322e9 Do not compute checksums on macOS 2024-01-28 12:13:07 +11:00
grossmj 8eb5f10971 Add multiprocessing.set_start_method() 2024-01-28 12:13:07 +11:00
grossmj cc4783ab98 Bump version to v2.2.45.dev2 2024-01-28 12:13:07 +11:00
grossmj 19792f328d Have freeze support for macOS as well 2024-01-28 12:13:07 +11:00
grossmj 596d1274a3 Catch exceptions when computing image checksums. Ref https://github.com/GNS3/gns3-server/issues/2228 2024-01-28 12:13:07 +11:00
grossmj 2f765747b8 Add freeze_support() for multiprocessing 2024-01-28 12:13:06 +11:00
grossmj 4fe57b6a15 Development on 2.2.45.dev1 2024-01-28 12:13:06 +11:00
grossmj 1177626a53 Release v2.2.44 2024-01-28 12:13:06 +11:00
grossmj c4cc346864 Sync appliances 2024-01-28 12:13:06 +11:00
grossmj 8915dfffa5 Bundle web-ui v2.2.44 2024-01-28 12:13:05 +11:00
grossmj ff027ebd17 Upgrade sentry-sdk 2024-01-28 12:13:05 +11:00
grossmj 27d5ac537f Non-blocking checksums computation when server starts. Fixes #2228 2024-01-28 12:13:05 +11:00
grossmj fe246cd413 Fix timeout issue when creating Qemu disk image. Fixes https://github.com/GNS3/gns3-server/issues/2313 2024-01-28 12:13:05 +11:00
grossmj 2bbb560b8e Support for web socket console over HTTPS 2024-01-28 12:13:04 +11:00
grossmj 1624c7d6ad Add back script create_cert.sh 2024-01-28 12:13:04 +11:00
grossmj 2a3bb81076 Bundle web-ui 2024-01-28 12:13:04 +11:00
grossmj e0a0dd83d7 Use Python 3.8 in appveyor.yml 2024-01-28 12:13:04 +11:00
grossmj 16ea395618 Upgrade sentry-sdk, psutil and distro dependencies 2024-01-27 17:04:02 +11:00
Jeremy Grossmann 9dd8da4f6e Merge pull request #2340 from spikefishjohn/patch-3
Update telnet_server.py
2024-01-26 17:55:11 +11:00
John Fleming 54abf85523 Update telnet_server.py
Maybe use the correct object name this time for the socket objects.
2024-01-25 01:41:57 -05:00
Jeremy Grossmann 385fffec56 Merge pull request #2339 from spikefishjohn/patch-2
Update telnet_server.py
2024-01-24 11:53:59 +11:00
John Fleming ac86717bc0 Update telnet_server.py
Set tcp keepalive timers to 60 seconds. Seems to default to 2 hours on ubuntu 22. Most firewalls will age out an idle tcp session at 1 hour.

Will not address telnet console failing after a tcp session has failed (TimeoutError).
2024-01-23 13:15:17 -05:00
grossmj 7b7af33920 Development on 2.2.46.dev1 2024-01-14 23:45:35 +11:00
Jeremy Grossmann 85fd3ef4a4 Merge pull request #2338 from GNS3/2.2
Release v2.2.45
2024-01-14 22:02:14 +11:00
grossmj fbd8f6ce28 Release v2.2.45 2024-01-12 21:38:26 +11:00
grossmj 195da24910 Bundle web-ui v2.2.45 2024-01-12 21:34:11 +11:00
grossmj b4c7609aeb Remove old web-ui files 2024-01-12 21:29:04 +11:00
grossmj cd9c4c84b6 Bundle web-ui v2.2.45 2024-01-12 21:21:18 +11:00
grossmj 2566de0f5a Sync appliances 2024-01-12 21:13:52 +11:00
grossmj 6a069d0af6 Fix mouse offset issues with VNC in Qemu. Fixes #2335 2024-01-12 16:18:32 +11:00
grossmj 2789b3802a Fix issues when generating docs 2024-01-12 16:14:01 +11:00
grossmj 9e1a1337d4 Update readthedocs.yml to use Python 3.12 2024-01-12 15:27:41 +11:00
Jeremy Grossmann 466eb8128e Merge pull request #2336 from GNS3/fix/2319
Refactor project notifications
2024-01-12 13:38:51 +11:00
grossmj e41227b5bd Update readthedocs.yml 2024-01-12 13:32:15 +11:00
grossmj 78a3b8e824 Update documentation 2024-01-12 13:21:34 +11:00
grossmj 4c149e1614 Add project.created, project.opened and project.deleted controller notification stream.
Move project.updated and project.closed from project notification to controller notification stream.
2024-01-12 13:16:55 +11:00
grossmj 473fa98eda Do not stop searching for Qemu binaries if one binary cannot be executed. Ref #2306 2024-01-11 23:11:56 +11:00
grossmj 13d9afd8bc Fix Ethernet switch and Ethernet hub port validations. Fixes #2334 2024-01-11 22:40:38 +11:00
grossmj b4edbbbaa7 Bundle dev version of the web-ui 2023-12-07 12:34:52 +10:00
grossmj 02e19800fb Update CORS policy 2023-12-06 22:33:55 +10:00
grossmj 24bb0ca419 Add custom executable paths on Windows 2023-12-05 21:24:40 +10:00
grossmj 6c5f75bf43 Upgrade sentry-sdk and aiohttp 2023-11-22 10:32:50 +10:00
grossmj 7afdcbb3d3 Development in 2.2.45.dev3 2023-11-07 19:11:57 +10:00
Jeremy Grossmann de27a57a00 Merge pull request #2322 from GNS3/release-v2.2.44.1
Release v2.2.44.1
2023-11-07 18:35:29 +10:00
grossmj c88f76b740 Release v2.2.44.1 2023-11-07 14:59:28 +10:00
grossmj b81cc14cef Do not compute checksums on macOS 2023-11-07 14:30:39 +10:00
grossmj aa133c3b8a Add multiprocessing.set_start_method() 2023-11-07 13:33:43 +10:00
grossmj 7449064ea2 Bump version to v2.2.45.dev2 2023-11-07 12:21:39 +10:00
grossmj db315e3c3c Have freeze support for macOS as well 2023-11-07 11:17:48 +10:00
grossmj c437482e85 Catch exceptions when computing image checksums. Ref https://github.com/GNS3/gns3-server/issues/2228 2023-11-07 11:08:47 +10:00
Jeremy Grossmann 46d9ada6d8 Merge pull request #2321 from Xatrekak/master
Fixed updating system and GNS3 via welcome.py.
2023-11-07 10:49:00 +10:00
grossmj aac6fbfc31 Add freeze_support() for multiprocessing 2023-11-07 10:42:53 +10:00
Xatrekak 76bd5921c5 Fixed updating system and GNS3. 2023-11-06 19:02:29 -05:00
Jeremy Grossmann af3a618306 Merge pull request #2316 from GNS3/release-v2.2.44
Release v2.2.44
2023-11-06 17:05:54 +10:00
grossmj 3c4b5db1ca Development on 2.2.45.dev1 2023-11-06 17:00:17 +10:00
grossmj 5c8abdc6fd Release v2.2.44 2023-11-06 16:02:23 +10:00
grossmj f80f41b5b3 Sync appliances 2023-11-06 15:58:21 +10:00
grossmj 503373a6e9 Bundle web-ui v2.2.44 2023-11-06 15:53:51 +10:00
grossmj 8236c85b5f Upgrade sentry-sdk 2023-11-06 15:44:30 +10:00
Jeremy Grossmann 531499bbfb Merge pull request #2314 from Xatrekak/master
[Fix] an issue where the shell option in dialog failed to drop you back to bash.
2023-11-06 13:01:35 +10:00
grossmj ae825b0080 Non-blocking checksums computation when server starts. Fixes #2228 2023-11-06 12:32:23 +10:00
Dustin 7ad3afbdef Update welcome.py
Fixed an issue where the shell option in dialog failed to drop you back to bash.
2023-11-05 13:35:06 -05:00
grossmj 191feed669 Fix timeout issue when creating Qemu disk image. Fixes https://github.com/GNS3/gns3-server/issues/2313 2023-11-05 15:41:46 +10:00
grossmj 3b22bcfe96 Support for web socket console over HTTPS 2023-11-03 14:40:40 +10:00
grossmj 0f07b9e019 Add back script create_cert.sh 2023-11-03 12:31:34 +10:00
grossmj 8676a3dccf Bundle web-ui 2023-11-02 17:40:47 +10:00
grossmj b0dbf59ac4 Use Python 3.8 in appveyor.yml 2023-10-31 14:48:08 +10:00
Jeremy Grossmann 0e18762b36 Merge pull request #2308 from Xatrekak/master
Update remote-install.sh
2023-10-31 09:19:55 +10:00
Dustin cbc7e59d3f Update remote-install.sh
Removed an extra slash at the end when setting the user home directory. This was causing unexpected behavior for other scrips as ~ was aliased to /opt/gns3/ instead of the expected  /opt/gns3.

This caused an extra / to appear in commands unexpectedly.
2023-10-30 11:00:45 -04:00
Jeremy Grossmann 14fd165f2a Merge pull request #2307 from GNS3/fix/3521
Allow disabling hardware virtualization check
2023-10-30 15:03:50 +10:00
grossmj 7c49a9160c Allow disabling hardware virtualization check 2023-10-30 14:57:11 +10:00
Jeremy Grossmann 5a6e945db2 Merge pull request #2304 from GNS3/upgrade-python-api-doc
Upgrade to Python 3.8 for API doc publishing
2023-10-27 14:46:52 +10:00
grossmj 86c0b90951 Use Python 3.8 to publish API doc 2023-10-27 14:42:22 +10:00
grossmj ed99a98fe1 Sync appliances 2023-10-27 13:20:15 +10:00
Jeremy Grossmann 19edc193f9 Merge pull request #2303 from GNS3/fix/1484
Fix L2IOU "failed code signing checks"
2023-10-26 15:13:12 +10:00
grossmj 3f50319990 Fix L2IOU "failed code signing checks" when IOU base file name is >= 63 characters 2023-10-26 15:05:10 +10:00
Jeremy Grossmann 248737c34b Merge pull request #2296 from ventaquil/feature/add-qemu-igb-nic
Add Qemu IGB network device
2023-10-24 17:23:00 +10:00
Jeremy Grossmann 240708112c Merge branch '2.2' into feature/add-qemu-igb-nic 2023-10-24 17:14:27 +10:00
grossmj c759c4e3f6 Upgrade to actions/checkout@v3 and actions/setup-python@v3 2023-10-23 16:17:31 +10:00
grossmj 34ee75e1f1 Fix tests running on Python 3.12 2023-10-23 16:12:12 +10:00
grossmj 4af5edbc03 Install aiohttp 3.9.0b0 when running on Python 3.12 2023-10-23 15:21:06 +10:00
grossmj 0d15f40930 Change "ip cef" to "no ip cef" in IOU default configs. Fixes #2298 2023-10-23 15:16:49 +10:00
Konrad Goławski 737664a3d4 Add Qemu IGB network device 2023-10-12 11:35:53 +02:00
94 changed files with 1462 additions and 443 deletions

No files matched your search

@@ -18,7 +18,7 @@ jobs:
ref: "gh-pages"
- uses: actions/setup-python@v3
with:
python-version: 3.7
python-version: 3.8
- name: Merge changes from 3.0 branch
run: |
git config user.name github-actions
+4 -4
View File
@@ -13,15 +13,15 @@ on:
jobs:
build:
runs-on: ubuntu-20.04 # Downgrade Ubuntu to 20.04 to fix missing Python 3.6
runs-on: ubuntu-22.04
strategy:
matrix:
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
+43
View File
@@ -1,5 +1,48 @@
# Change Log
## 2.2.46 26/02/2024
* Bundle web-ui v2.2.46
* Save empty directories when exporting a project
* Backport from v3: install Docker resources in a writable location at runtime.
* Use Docker API v1.24 to get version.
* Drop support for Python 3.6
* Address the telnet console bug.
* Update welcome.py
* Update remote-install.sh
* Use Python 3.8 to publish API doc
* Upgrade sentry-sdk, psutil and distro dependencies
## 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
## 2.2.44.1 07/11/2023
* Catch exceptions when computing image checksums. Ref https://github.com/GNS3/gns3-server/issues/2228
* Add freeze_support() for multiprocessing
## 2.2.44 06/11/2023
* Bundle web-ui v2.2.44
* Non-blocking checksums computation when server starts. Fixes #2228
* Fix timeout issue when creating Qemu disk image. Fixes https://github.com/GNS3/gns3-server/issues/2313
* Support for web socket console over HTTPS
* Add back script create_cert.sh
* Allow disabling hardware virtualization check
* Fix L2IOU "failed code signing checks" when IOU base file name is >= 63 characters
* Change "ip cef" to "no ip cef" in IOU default configs. Fixes #2298
* Add Qemu IGB network device
* Add Python 3.12 support.
* Fix issue with importlib.resources.files() and Python 3.9
## 2.2.43 19/09/2023
* Force English output for VBoxManage. Fixes #2266
+1 -1
View File
@@ -5,7 +5,7 @@ image: Visual Studio 2022
platform: x64
environment:
PYTHON: "C:\\Python37-x64"
PYTHON: "C:\\Python38-x64"
DISTUTILS_USE_SDK: "1"
API_TOKEN:
secure: VEKn4bYH3QO0ixtQW5ni4Enmn8cS1NlZV246ludBDgQ=
+3
View File
@@ -62,6 +62,9 @@ default_nat_interface = vmnet10
; Enable the built-in templates
enable_builtin_templates = True
; check if hardware virtualization is used by other emulators (KVM, VMware or VirtualBox)
hardware_virtualization_check = True
[VPCS]
; VPCS executable location, default: search in PATH
;vpcs_path = vpcs
+5 -4
View File
@@ -11,7 +11,8 @@
10
]
},
"link_id": "b76bd8b1-2171-4361-9228-801713d23079",
"link_id": "c3f1b38a-160d-4a67-baa0-34fc3d9759ed",
"link_style": {},
"link_type": "ethernet",
"nodes": [
{
@@ -21,7 +22,7 @@
"x": 64,
"y": 0
},
"node_id": "8b77b480-361e-488b-96b1-a769890e11ec",
"node_id": "481e5898-cd97-4351-8b1e-0c9e77fc7c58",
"port_number": 3
},
{
@@ -30,10 +31,10 @@
"style": "font-family: TypeWriter;font-size: 10.0;font-weight: bold;fill: #000000;fill-opacity: 1.0;",
"text": "2/4"
},
"node_id": "b4688a3d-0af8-4ddc-b85f-e26dc1031c4c",
"node_id": "63f7b8ab-146d-4142-b8c5-cf387ac1d963",
"port_number": 4
}
],
"project_id": "85333131-b83a-4112-9a51-184ba0c536a8",
"project_id": "292936d2-9f54-4e29-959f-b59ed9ac5e6f",
"suspend": false
}
+1 -1
View File
@@ -1,3 +1,3 @@
{
"message": "Warning ASA 8 is not officialy supported by GNS3"
"message": "Warning ASA 8 is not officially supported by GNS3"
}
+3
View File
@@ -0,0 +1,3 @@
{
"a": "b"
}
+3
View File
@@ -0,0 +1,3 @@
{
"a": "b"
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -23,7 +23,7 @@ Types
+++++++++
EthernetSwitchPort
^^^^^^^^^^^^^^^^^^^^^^
Ethernet port
Ethernet switch port
.. raw:: html
@@ -56,7 +56,7 @@ Types
+++++++++
EthernetSwitchPort
^^^^^^^^^^^^^^^^^^^^^^
Ethernet port
Ethernet switch port
.. raw:: html
@@ -23,7 +23,7 @@ Input
<table>
<tr> <th>Name</th> <th>Mandatory</th> <th>Type</th> <th>Description</th> </tr>
<tr><td>application_id</td> <td> </td> <td>['integer', 'null']</td> <td>Application ID for running IOU image</td> </tr>
<tr><td>application_id</td> <td>&#10004;</td> <td>['integer', 'null']</td> <td>Application ID for running IOU image</td> </tr>
<tr><td>console</td> <td> </td> <td>['integer', 'null']</td> <td>Console TCP port</td> </tr>
<tr><td>console_type</td> <td> </td> <td>enum</td> <td>Possible values: telnet, none</td> </tr>
<tr><td>ethernet_adapters</td> <td> </td> <td>integer</td> <td>How many ethernet adapters are connected to the IOU</td> </tr>
+2
View File
@@ -35,6 +35,8 @@ Input
<table>
<tr> <th>Name</th> <th>Mandatory</th> <th>Type</th> <th>Description</th> </tr>
<tr><td>auto_close</td> <td> </td> <td>boolean</td> <td>Project auto close</td> </tr>
<tr><td>auto_open</td> <td> </td> <td>boolean</td> <td>Project open when GNS3 start</td> </tr>
<tr><td>auto_start</td> <td> </td> <td>boolean</td> <td>Project start when opened</td> </tr>
<tr><td>drawing_grid_size</td> <td> </td> <td>integer</td> <td>Grid size for the drawing area for drawings</td> </tr>
<tr><td>grid_size</td> <td> </td> <td>integer</td> <td>Grid size for the drawing area for nodes</td> </tr>
<tr><td>name</td> <td>&#10004;</td> <td>['string', 'null']</td> <td>Project name</td> </tr>
@@ -34,6 +34,7 @@ Input
<tr><td>console_type</td> <td> </td> <td>enum</td> <td>Possible values: telnet, vnc, spice, spice+agent, none</td> </tr>
<tr><td>cpu_throttling</td> <td> </td> <td>['integer', 'null']</td> <td>Percentage of CPU allowed for QEMU</td> </tr>
<tr><td>cpus</td> <td> </td> <td>['integer', 'null']</td> <td>Number of vCPUs</td> </tr>
<tr><td>create_config_disk</td> <td> </td> <td>['boolean', 'null']</td> <td>Automatically create a config disk on HDD disk interface (secondary slave)</td> </tr>
<tr><td>custom_adapters</td> <td> </td> <td>array</td> <td></td> </tr>
<tr><td>hda_disk_image</td> <td> </td> <td>string</td> <td>QEMU hda disk image path</td> </tr>
<tr><td>hda_disk_image_md5sum</td> <td> </td> <td>['string', 'null']</td> <td>QEMU hda disk image checksum</td> </tr>
@@ -63,6 +64,9 @@ Input
<tr><td>process_priority</td> <td> </td> <td>enum</td> <td>Possible values: realtime, very high, high, normal, low, very low, null</td> </tr>
<tr><td>qemu_path</td> <td> </td> <td>['string', 'null']</td> <td>Path to QEMU</td> </tr>
<tr><td>ram</td> <td> </td> <td>['integer', 'null']</td> <td>Amount of RAM in MB</td> </tr>
<tr><td>replicate_network_connection_state</td> <td> </td> <td>['boolean', 'null']</td> <td>Replicate the network connection state for links in Qemu</td> </tr>
<tr><td>tpm</td> <td> </td> <td>['boolean', 'null']</td> <td>Enable the Trusted Platform Module (TPM) in Qemu</td> </tr>
<tr><td>uefi</td> <td> </td> <td>['boolean', 'null']</td> <td>Enable the UEFI boot mode in Qemu</td> </tr>
<tr><td>usage</td> <td> </td> <td>string</td> <td>How to use the Qemu VM</td> </tr>
</table>
@@ -84,6 +88,7 @@ Output
<tr><td>console_type</td> <td>&#10004;</td> <td>enum</td> <td>Possible values: telnet, vnc, spice, spice+agent, none</td> </tr>
<tr><td>cpu_throttling</td> <td>&#10004;</td> <td>integer</td> <td>Percentage of CPU allowed for QEMU</td> </tr>
<tr><td>cpus</td> <td>&#10004;</td> <td>['integer', 'null']</td> <td>Number of vCPUs</td> </tr>
<tr><td>create_config_disk</td> <td>&#10004;</td> <td>['boolean', 'null']</td> <td>Automatically create a config disk on HDD disk interface (secondary slave)</td> </tr>
<tr><td>hda_disk_image</td> <td>&#10004;</td> <td>string</td> <td>QEMU hda disk image path</td> </tr>
<tr><td>hda_disk_image_md5sum</td> <td>&#10004;</td> <td>['string', 'null']</td> <td>QEMU hda disk image checksum</td> </tr>
<tr><td>hda_disk_interface</td> <td>&#10004;</td> <td>string</td> <td>QEMU hda interface</td> </tr>
@@ -113,8 +118,11 @@ Output
<tr><td>project_id</td> <td>&#10004;</td> <td>string</td> <td>Project UUID</td> </tr>
<tr><td>qemu_path</td> <td>&#10004;</td> <td>string</td> <td>Path to QEMU</td> </tr>
<tr><td>ram</td> <td>&#10004;</td> <td>integer</td> <td>Amount of RAM in MB</td> </tr>
<tr><td>replicate_network_connection_state</td> <td>&#10004;</td> <td>boolean</td> <td>Replicate the network connection state for links in Qemu</td> </tr>
<tr><td>save_vm_state</td> <td> </td> <td>['boolean', 'null']</td> <td>Save VM state support</td> </tr>
<tr><td>status</td> <td>&#10004;</td> <td>enum</td> <td>Possible values: started, stopped, suspended</td> </tr>
<tr><td>tpm</td> <td>&#10004;</td> <td>boolean</td> <td>Enable the Trusted Platform Module (TPM) in Qemu</td> </tr>
<tr><td>uefi</td> <td>&#10004;</td> <td>boolean</td> <td>Enable the UEFI boot mode in Qemu</td> </tr>
<tr><td>usage</td> <td>&#10004;</td> <td>string</td> <td>How to use the QEMU VM</td> </tr>
</table>
@@ -36,6 +36,7 @@ Output
<tr><td>console_type</td> <td>&#10004;</td> <td>enum</td> <td>Possible values: telnet, vnc, spice, spice+agent, none</td> </tr>
<tr><td>cpu_throttling</td> <td>&#10004;</td> <td>integer</td> <td>Percentage of CPU allowed for QEMU</td> </tr>
<tr><td>cpus</td> <td>&#10004;</td> <td>['integer', 'null']</td> <td>Number of vCPUs</td> </tr>
<tr><td>create_config_disk</td> <td>&#10004;</td> <td>['boolean', 'null']</td> <td>Automatically create a config disk on HDD disk interface (secondary slave)</td> </tr>
<tr><td>hda_disk_image</td> <td>&#10004;</td> <td>string</td> <td>QEMU hda disk image path</td> </tr>
<tr><td>hda_disk_image_md5sum</td> <td>&#10004;</td> <td>['string', 'null']</td> <td>QEMU hda disk image checksum</td> </tr>
<tr><td>hda_disk_interface</td> <td>&#10004;</td> <td>string</td> <td>QEMU hda interface</td> </tr>
@@ -65,8 +66,11 @@ Output
<tr><td>project_id</td> <td>&#10004;</td> <td>string</td> <td>Project UUID</td> </tr>
<tr><td>qemu_path</td> <td>&#10004;</td> <td>string</td> <td>Path to QEMU</td> </tr>
<tr><td>ram</td> <td>&#10004;</td> <td>integer</td> <td>Amount of RAM in MB</td> </tr>
<tr><td>replicate_network_connection_state</td> <td>&#10004;</td> <td>boolean</td> <td>Replicate the network connection state for links in Qemu</td> </tr>
<tr><td>save_vm_state</td> <td> </td> <td>['boolean', 'null']</td> <td>Save VM state support</td> </tr>
<tr><td>status</td> <td>&#10004;</td> <td>enum</td> <td>Possible values: started, stopped, suspended</td> </tr>
<tr><td>tpm</td> <td>&#10004;</td> <td>boolean</td> <td>Enable the Trusted Platform Module (TPM) in Qemu</td> </tr>
<tr><td>uefi</td> <td>&#10004;</td> <td>boolean</td> <td>Enable the UEFI boot mode in Qemu</td> </tr>
<tr><td>usage</td> <td>&#10004;</td> <td>string</td> <td>How to use the QEMU VM</td> </tr>
</table>
@@ -110,6 +114,7 @@ Input
<tr><td>console_type</td> <td> </td> <td>enum</td> <td>Possible values: telnet, vnc, spice, spice+agent, none</td> </tr>
<tr><td>cpu_throttling</td> <td> </td> <td>['integer', 'null']</td> <td>Percentage of CPU allowed for QEMU</td> </tr>
<tr><td>cpus</td> <td> </td> <td>['integer', 'null']</td> <td>Number of vCPUs</td> </tr>
<tr><td>create_config_disk</td> <td> </td> <td>['boolean', 'null']</td> <td>Automatically create a config disk on HDD disk interface (secondary slave)</td> </tr>
<tr><td>custom_adapters</td> <td> </td> <td>array</td> <td></td> </tr>
<tr><td>hda_disk_image</td> <td> </td> <td>string</td> <td>QEMU hda disk image path</td> </tr>
<tr><td>hda_disk_image_md5sum</td> <td> </td> <td>['string', 'null']</td> <td>QEMU hda disk image checksum</td> </tr>
@@ -138,6 +143,9 @@ Input
<tr><td>process_priority</td> <td> </td> <td>enum</td> <td>Possible values: realtime, very high, high, normal, low, very low, null</td> </tr>
<tr><td>qemu_path</td> <td> </td> <td>['string', 'null']</td> <td>Path to QEMU</td> </tr>
<tr><td>ram</td> <td> </td> <td>['integer', 'null']</td> <td>Amount of RAM in MB</td> </tr>
<tr><td>replicate_network_connection_state</td> <td> </td> <td>['boolean', 'null']</td> <td>Replicate the network connection state for links in Qemu</td> </tr>
<tr><td>tpm</td> <td> </td> <td>['boolean', 'null']</td> <td>Enable the Trusted Platform Module (TPM) in Qemu</td> </tr>
<tr><td>uefi</td> <td> </td> <td>['boolean', 'null']</td> <td>Enable the UEFI boot mode in Qemu</td> </tr>
<tr><td>usage</td> <td> </td> <td>string</td> <td>How to use the QEMU VM</td> </tr>
</table>
@@ -159,6 +167,7 @@ Output
<tr><td>console_type</td> <td>&#10004;</td> <td>enum</td> <td>Possible values: telnet, vnc, spice, spice+agent, none</td> </tr>
<tr><td>cpu_throttling</td> <td>&#10004;</td> <td>integer</td> <td>Percentage of CPU allowed for QEMU</td> </tr>
<tr><td>cpus</td> <td>&#10004;</td> <td>['integer', 'null']</td> <td>Number of vCPUs</td> </tr>
<tr><td>create_config_disk</td> <td>&#10004;</td> <td>['boolean', 'null']</td> <td>Automatically create a config disk on HDD disk interface (secondary slave)</td> </tr>
<tr><td>hda_disk_image</td> <td>&#10004;</td> <td>string</td> <td>QEMU hda disk image path</td> </tr>
<tr><td>hda_disk_image_md5sum</td> <td>&#10004;</td> <td>['string', 'null']</td> <td>QEMU hda disk image checksum</td> </tr>
<tr><td>hda_disk_interface</td> <td>&#10004;</td> <td>string</td> <td>QEMU hda interface</td> </tr>
@@ -188,8 +197,11 @@ Output
<tr><td>project_id</td> <td>&#10004;</td> <td>string</td> <td>Project UUID</td> </tr>
<tr><td>qemu_path</td> <td>&#10004;</td> <td>string</td> <td>Path to QEMU</td> </tr>
<tr><td>ram</td> <td>&#10004;</td> <td>integer</td> <td>Amount of RAM in MB</td> </tr>
<tr><td>replicate_network_connection_state</td> <td>&#10004;</td> <td>boolean</td> <td>Replicate the network connection state for links in Qemu</td> </tr>
<tr><td>save_vm_state</td> <td> </td> <td>['boolean', 'null']</td> <td>Save VM state support</td> </tr>
<tr><td>status</td> <td>&#10004;</td> <td>enum</td> <td>Possible values: started, stopped, suspended</td> </tr>
<tr><td>tpm</td> <td>&#10004;</td> <td>boolean</td> <td>Enable the Trusted Platform Module (TPM) in Qemu</td> </tr>
<tr><td>uefi</td> <td>&#10004;</td> <td>boolean</td> <td>Enable the UEFI boot mode in Qemu</td> </tr>
<tr><td>usage</td> <td>&#10004;</td> <td>string</td> <td>How to use the QEMU VM</td> </tr>
</table>
@@ -36,6 +36,7 @@ Output
<tr><td>console_type</td> <td>&#10004;</td> <td>enum</td> <td>Possible values: telnet, vnc, spice, spice+agent, none</td> </tr>
<tr><td>cpu_throttling</td> <td>&#10004;</td> <td>integer</td> <td>Percentage of CPU allowed for QEMU</td> </tr>
<tr><td>cpus</td> <td>&#10004;</td> <td>['integer', 'null']</td> <td>Number of vCPUs</td> </tr>
<tr><td>create_config_disk</td> <td>&#10004;</td> <td>['boolean', 'null']</td> <td>Automatically create a config disk on HDD disk interface (secondary slave)</td> </tr>
<tr><td>hda_disk_image</td> <td>&#10004;</td> <td>string</td> <td>QEMU hda disk image path</td> </tr>
<tr><td>hda_disk_image_md5sum</td> <td>&#10004;</td> <td>['string', 'null']</td> <td>QEMU hda disk image checksum</td> </tr>
<tr><td>hda_disk_interface</td> <td>&#10004;</td> <td>string</td> <td>QEMU hda interface</td> </tr>
@@ -65,8 +66,11 @@ Output
<tr><td>project_id</td> <td>&#10004;</td> <td>string</td> <td>Project UUID</td> </tr>
<tr><td>qemu_path</td> <td>&#10004;</td> <td>string</td> <td>Path to QEMU</td> </tr>
<tr><td>ram</td> <td>&#10004;</td> <td>integer</td> <td>Amount of RAM in MB</td> </tr>
<tr><td>replicate_network_connection_state</td> <td>&#10004;</td> <td>boolean</td> <td>Replicate the network connection state for links in Qemu</td> </tr>
<tr><td>save_vm_state</td> <td> </td> <td>['boolean', 'null']</td> <td>Save VM state support</td> </tr>
<tr><td>status</td> <td>&#10004;</td> <td>enum</td> <td>Possible values: started, stopped, suspended</td> </tr>
<tr><td>tpm</td> <td>&#10004;</td> <td>boolean</td> <td>Enable the Trusted Platform Module (TPM) in Qemu</td> </tr>
<tr><td>uefi</td> <td>&#10004;</td> <td>boolean</td> <td>Enable the UEFI boot mode in Qemu</td> </tr>
<tr><td>usage</td> <td>&#10004;</td> <td>string</td> <td>How to use the QEMU VM</td> </tr>
</table>
@@ -47,6 +47,7 @@ Input
<tr><td>capturing</td> <td> </td> <td>boolean</td> <td>Read only property. True if a capture running on the link</td> </tr>
<tr><td>filters</td> <td> </td> <td>object</td> <td>Packet filter. This allow to simulate latency and errors</td> </tr>
<tr><td>link_id</td> <td> </td> <td>string</td> <td>Link UUID</td> </tr>
<tr><td>link_style</td> <td> </td> <td>object</td> <td>Link line style</td> </tr>
<tr><td>link_type</td> <td> </td> <td>enum</td> <td>Possible values: ethernet, serial</td> </tr>
<tr><td>nodes</td> <td> </td> <td>array</td> <td>List of the VMS</td> </tr>
<tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr>
@@ -65,6 +66,7 @@ Output
<tr><td>capturing</td> <td> </td> <td>boolean</td> <td>Read only property. True if a capture running on the link</td> </tr>
<tr><td>filters</td> <td> </td> <td>object</td> <td>Packet filter. This allow to simulate latency and errors</td> </tr>
<tr><td>link_id</td> <td> </td> <td>string</td> <td>Link UUID</td> </tr>
<tr><td>link_style</td> <td> </td> <td>object</td> <td>Link line style</td> </tr>
<tr><td>link_type</td> <td> </td> <td>enum</td> <td>Possible values: ethernet, serial</td> </tr>
<tr><td>nodes</td> <td> </td> <td>array</td> <td>List of the VMS</td> </tr>
<tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr>
@@ -30,6 +30,7 @@ Output
<tr><td>capturing</td> <td> </td> <td>boolean</td> <td>Read only property. True if a capture running on the link</td> </tr>
<tr><td>filters</td> <td> </td> <td>object</td> <td>Packet filter. This allow to simulate latency and errors</td> </tr>
<tr><td>link_id</td> <td> </td> <td>string</td> <td>Link UUID</td> </tr>
<tr><td>link_style</td> <td> </td> <td>object</td> <td>Link line style</td> </tr>
<tr><td>link_type</td> <td> </td> <td>enum</td> <td>Possible values: ethernet, serial</td> </tr>
<tr><td>nodes</td> <td> </td> <td>array</td> <td>List of the VMS</td> </tr>
<tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr>
@@ -69,6 +70,7 @@ Input
<tr><td>capturing</td> <td> </td> <td>boolean</td> <td>Read only property. True if a capture running on the link</td> </tr>
<tr><td>filters</td> <td> </td> <td>object</td> <td>Packet filter. This allow to simulate latency and errors</td> </tr>
<tr><td>link_id</td> <td> </td> <td>string</td> <td>Link UUID</td> </tr>
<tr><td>link_style</td> <td> </td> <td>object</td> <td>Link line style</td> </tr>
<tr><td>link_type</td> <td> </td> <td>enum</td> <td>Possible values: ethernet, serial</td> </tr>
<tr><td>nodes</td> <td> </td> <td>array</td> <td>List of the VMS</td> </tr>
<tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr>
@@ -87,6 +89,7 @@ Output
<tr><td>capturing</td> <td> </td> <td>boolean</td> <td>Read only property. True if a capture running on the link</td> </tr>
<tr><td>filters</td> <td> </td> <td>object</td> <td>Packet filter. This allow to simulate latency and errors</td> </tr>
<tr><td>link_id</td> <td> </td> <td>string</td> <td>Link UUID</td> </tr>
<tr><td>link_style</td> <td> </td> <td>object</td> <td>Link line style</td> </tr>
<tr><td>link_type</td> <td> </td> <td>enum</td> <td>Possible values: ethernet, serial</td> </tr>
<tr><td>nodes</td> <td> </td> <td>array</td> <td>List of the VMS</td> </tr>
<tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr>
@@ -39,6 +39,7 @@ Output
<tr><td>capturing</td> <td> </td> <td>boolean</td> <td>Read only property. True if a capture running on the link</td> </tr>
<tr><td>filters</td> <td> </td> <td>object</td> <td>Packet filter. This allow to simulate latency and errors</td> </tr>
<tr><td>link_id</td> <td> </td> <td>string</td> <td>Link UUID</td> </tr>
<tr><td>link_style</td> <td> </td> <td>object</td> <td>Link line style</td> </tr>
<tr><td>link_type</td> <td> </td> <td>enum</td> <td>Possible values: ethernet, serial</td> </tr>
<tr><td>nodes</td> <td> </td> <td>array</td> <td>List of the VMS</td> </tr>
<tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr>
@@ -19,6 +19,8 @@ Input
<table>
<tr> <th>Name</th> <th>Mandatory</th> <th>Type</th> <th>Description</th> </tr>
<tr><td>auto_close</td> <td> </td> <td>boolean</td> <td>Project auto close</td> </tr>
<tr><td>auto_open</td> <td> </td> <td>boolean</td> <td>Project open when GNS3 start</td> </tr>
<tr><td>auto_start</td> <td> </td> <td>boolean</td> <td>Project start when opened</td> </tr>
<tr><td>drawing_grid_size</td> <td> </td> <td>integer</td> <td>Grid size for the drawing area for drawings</td> </tr>
<tr><td>grid_size</td> <td> </td> <td>integer</td> <td>Grid size for the drawing area for nodes</td> </tr>
<tr><td>name</td> <td>&#10004;</td> <td>['string', 'null']</td> <td>Project name</td> </tr>
@@ -24,11 +24,14 @@ Input
<table>
<tr> <th>Name</th> <th>Mandatory</th> <th>Type</th> <th>Description</th> </tr>
<tr><td>auto_close</td> <td> </td> <td>boolean</td> <td>Project auto close</td> </tr>
<tr><td>auto_open</td> <td> </td> <td>boolean</td> <td>Project open when GNS3 start</td> </tr>
<tr><td>auto_start</td> <td> </td> <td>boolean</td> <td>Project start when opened</td> </tr>
<tr><td>drawing_grid_size</td> <td> </td> <td>integer</td> <td>Grid size for the drawing area for drawings</td> </tr>
<tr><td>grid_size</td> <td> </td> <td>integer</td> <td>Grid size for the drawing area for nodes</td> </tr>
<tr><td>name</td> <td>&#10004;</td> <td>['string', 'null']</td> <td>Project name</td> </tr>
<tr><td>path</td> <td> </td> <td>['string', 'null']</td> <td>Project directory</td> </tr>
<tr><td>project_id</td> <td> </td> <td>['string', 'null']</td> <td>Project UUID</td> </tr>
<tr><td>reset_mac_addresses</td> <td> </td> <td>boolean</td> <td>Reset MAC addresses for this project</td> </tr>
<tr><td>scene_height</td> <td> </td> <td>integer</td> <td>Height of the drawing area</td> </tr>
<tr><td>scene_width</td> <td> </td> <td>integer</td> <td>Width of the drawing area</td> </tr>
<tr><td>show_grid</td> <td> </td> <td>boolean</td> <td>Show the grid on the drawing area</td> </tr>
+32
View File
@@ -50,6 +50,38 @@ A compute has been deleted.
.. literalinclude:: api/notifications/compute.deleted.json
project.created
---------------
A project has been created.
.. literalinclude:: api/notifications/project.created.json
project.updated
---------------
A project has been updated.
.. literalinclude:: api/notifications/project.updated.json
project.closed
---------------
A project has been closed.
.. literalinclude:: api/notifications/project.closed.json
project.deleted
---------------
A project has been deleted.
.. literalinclude:: api/notifications/project.deleted.json
template.created
-----------------
+1 -1
View File
@@ -576,7 +576,7 @@ Read :doc:`project_notifications` for more information.
Where to find the endpoints?
###########################
############################
A list of all endpoints is available: :doc:`endpoints`
+23 -1
View File
@@ -103,7 +103,8 @@
"properties": {
"name": {
"type": "string",
"description": "Variable name"
"description": "Variable name",
"minLength": 1
},
"value": {
"type": "string",
@@ -387,6 +388,27 @@
"type": "boolean",
"description": "Suspend the link"
},
"link_style": {
"type": "object",
"description": "Link line style",
"items": {
"type": "object",
"properties": {
"color": {
"description": "Link line color",
"type": "string"
},
"width": {
"description": "Link line width",
"type": "integer"
},
"type": {
"description": "Link line type",
"type": "integer"
}
}
}
},
"filters": {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Packet filter. This allow to simulate latency and errors",
+1 -17
View File
@@ -100,28 +100,12 @@ A drawing has been deleted.
.. literalinclude:: api/notifications/drawing.deleted.json
project.updated
---------------
A project has been updated.
.. literalinclude:: api/notifications/project.updated.json
project.closed
---------------
A project has been closed.
.. literalinclude:: api/notifications/project.closed.json
snapshot.restored
--------------------------
A snapshot has been restored
.. literalinclude:: api/notifications/project.snapshot_restored.json
.. literalinclude:: api/notifications/snapshot.restored.json
log.error
---------
+1 -1
View File
@@ -11,7 +11,7 @@
"status": "stable",
"maintainer": "GNS3 Team",
"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": {
"adapter_type": "e1000",
"adapters": 4,
+14
View File
@@ -23,6 +23,14 @@
"kvm": "allow"
},
"images": [
{
"filename": "bird2-debian-2.14.qcow2",
"version": "2.14",
"md5sum": "029cf1756201ee79497c169502b08b88",
"filesize": 303717376,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "https://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/bird2-debian-2.14.qcow2"
},
{
"filename": "bird2-debian-2.0.12.qcow2",
"version": "2.0.12",
@@ -33,6 +41,12 @@
}
],
"versions": [
{
"name": "2.14",
"images": {
"hda_disk_image": "bird2-debian-2.14.qcow2"
}
},
{
"name": "2.0.12",
"images": {
+13
View File
@@ -26,6 +26,13 @@
"kvm": "require"
},
"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",
"version": "9.16.2 CML",
@@ -119,6 +126,12 @@
}
],
"versions": [
{
"name": "9.18.2 CML",
"images": {
"hda_disk_image": "asav9-18-2.qcow2"
}
},
{
"name": "9.16.2 CML",
"images": {
+13
View File
@@ -24,6 +24,13 @@
"kvm": "require"
},
"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",
"version": "17.06.05 8G",
@@ -54,6 +61,12 @@
}
],
"versions": [
{
"name": "17.09.01a 8G",
"images": {
"hda_disk_image": "c8000v-universalk9_8G_serial.17.09.01a.qcow2"
}
},
{
"name": "17.06.05 8G",
"images": {
@@ -24,6 +24,13 @@
"kvm": "require"
},
"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",
"version": "16.12.3",
@@ -159,6 +166,12 @@
}
],
"versions": [
{
"name": "17.03.06",
"images": {
"hda_disk_image": "csr1000v-universalk9.17.03.06-serial.qcow2"
}
},
{
"name": "16.12.3",
"images": {
@@ -26,6 +26,13 @@
"options": "-smp 4 -cpu host"
},
"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",
"version": "7.1.1",
@@ -105,6 +112,12 @@
}
],
"versions": [
{
"name": "7.7.1",
"images": {
"hda_disk_image": "xrv9k-fullk9-x-7.7.1.qcow2"
}
},
{
"name": "7.1.1",
"images": {
+70
View File
@@ -26,6 +26,13 @@
"kvm": "require"
},
"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",
"version": "9500v 10.1.1",
@@ -40,6 +47,34 @@
"filesize": 1990983680,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/10.1(1)"
},
{
"filename": "nexus9500v.9.3.13.qcow2",
"version": "9500v 9.3.13",
"md5sum": "bacf0f664ee34625c85a9f278b2466a2",
"filesize": 2248409088,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/9.3(13)"
},
{
"filename": "nexus9300v.9.3.13.qcow2",
"version": "9300v 9.3.13",
"md5sum": "d8ce30cb762df02d77ec27786a2435ad",
"filesize": 2248343552,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/9.3(13)"
},
{
"filename": "nexus9500v.9.3.12.qcow2",
"version": "9500v 9.3.12",
"md5sum": "452e5cb2a7a25feaa3ba0624a82ff9ca",
"filesize": 1997996032,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/9.3(12)"
},
{
"filename": "nexus9300v.9.3.12.qcow2",
"version": "9300v 9.3.12",
"md5sum": "7b6b5dad1001e11d6ebb54662616e9f2",
"filesize": 1997930496,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/9.3(12)"
},
{
"filename": "nexus9500v.9.3.9.qcow2",
"version": "9500v 9.3.9",
@@ -198,6 +233,13 @@
}
],
"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",
"images": {
@@ -212,6 +254,34 @@
"hda_disk_image": "nexus9300v.10.1.1.qcow2"
}
},
{
"name": "9500v 9.3.13",
"images": {
"bios_image": "OVMF-edk2-stable202305.fd",
"hda_disk_image": "nexus9500v.9.3.13.qcow2"
}
},
{
"name": "9300v 9.3.13",
"images": {
"bios_image": "OVMF-edk2-stable202305.fd",
"hda_disk_image": "nexus9300v.9.3.13.qcow2"
}
},
{
"name": "9500v 9.3.12",
"images": {
"bios_image": "OVMF-edk2-stable202305.fd",
"hda_disk_image": "nexus9500v.9.3.12.qcow2"
}
},
{
"name": "9300v 9.3.12",
"images": {
"bios_image": "OVMF-edk2-stable202305.fd",
"hda_disk_image": "nexus9300v.9.3.12.qcow2"
}
},
{
"name": "9500v 9.3.9",
"images": {
+7 -7
View File
@@ -24,12 +24,12 @@
},
"images": [
{
"filename": "debian-12.2.qcow2",
"version": "12.2",
"md5sum": "adf7716ec4a4e4e9e5ccfc7a1d7bd103",
"filesize": 286654464,
"filename": "debian-12.4.qcow2",
"version": "12.4",
"md5sum": "adcf7fdc25e10b3d2d9e2ef91168bffd",
"filesize": 286179840,
"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",
@@ -42,9 +42,9 @@
],
"versions": [
{
"name": "12.2",
"name": "12.4",
"images": {
"hda_disk_image": "debian-12.2.qcow2"
"hda_disk_image": "debian-12.4.qcow2"
}
},
{
+21 -4
View File
@@ -11,26 +11,36 @@
"status": "experimental",
"maintainer": "GNS3 Team",
"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",
"port_name_format": "fortyGigE0/{0}",
"qemu": {
"adapter_type": "e1000",
"adapters": 6,
"ram": 512,
"ram": 1024,
"hda_disk_interface": "ide",
"arch": "i386",
"console_type": "vnc",
"console_type": "telnet",
"boot_priority": "cd",
"kvm": "require"
},
"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",
"version": "9.8.0",
"md5sum": "b9b50eda0a73407dc381792ff7975e24",
"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"
},
{
@@ -43,6 +53,13 @@
}
],
"versions": [
{
"name": "9.13.0",
"images": {
"hda_disk_image": "empty30G.qcow2",
"cdrom_image": "FTOS-SI-9.13.0.0.iso"
}
},
{
"name": "9.8.0",
"images": {
+15 -45
View File
@@ -26,6 +26,14 @@
"options": "-nographic"
},
"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",
"version": "38-1.6",
@@ -34,30 +42,6 @@
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/38/Cloud/x86_64/images",
"direct_download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/38/Cloud/x86_64/images/Fedora-Cloud-Base-38-1.6.x86_64.qcow2"
},
{
"filename": "Fedora-Cloud-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",
"version": "1.0",
@@ -68,33 +52,19 @@
}
],
"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",
"images": {
"hda_disk_image": "Fedora-Cloud-Base-38-1.6.x86_64.qcow2",
"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"
}
}
]
}
+103 -4
View File
@@ -11,15 +11,16 @@
"product_url": "https://www.fortinet.com/products-services/products/management-reporting/fortianalyzer.html",
"registry_version": 4,
"status": "stable",
"maintainer": "GNS3 Team",
"maintainer_email": "developers@gns3.net",
"usage": "Default username is admin, no password is set.\n\n- Versions 7.0 and higher require:\n--RAM: 8192 MB\n--CPU:4",
"maintainer": "Ean Towne",
"maintainer_email": "ean.fortinet@gmail.com",
"usage": "Default username is admin, no password is set.\n\n- Versions lower than 7.0.x can reduce CPU/RAM",
"symbol": "fortinet.svg",
"port_name_format": "Port{port1}",
"qemu": {
"adapter_type": "e1000",
"adapters": 4,
"ram": 4096,
"ram": 16384,
"cpus": 4,
"hda_disk_interface": "virtio",
"hdb_disk_interface": "virtio",
"arch": "x86_64",
@@ -28,6 +29,27 @@
"kvm": "allow"
},
"images": [
{
"filename": "FAZ_VM64_KVM-v7.4.2-build2397-FORTINET.out.kvm.qcow2",
"version": "7.4.2",
"md5sum": "33b2938e19a6cb61d4d64e6998a54d23",
"filesize": 480096256,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAZ_VM64_KVM-v7.4.1-build2308-FORTINET.out.kvm.qcow2",
"version": "7.4.1",
"md5sum": "f30caac36854c2a0cc1e35c4ab5f310d",
"filesize": 435310592,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAZ_VM64_KVM-v7.2.4-build1460-FORTINET.out.kvm.qcow2",
"version": "7.2.4",
"md5sum": "d53bd5c61cc3f5e387557dfcfe9bc530",
"filesize": 363327488,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAZ_VM64_KVM-v7.2.2-build1334-FORTINET.out.kvm.qcow2",
"version": "7.2.2",
@@ -42,6 +64,20 @@
"filesize": 340631552,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAZ_VM64_KVM-v7.0.11-build0595-FORTINET.out.kvm.qcow2",
"version": "7.0.11",
"md5sum": "ae7ff37d00d0b518e9982a0785665fc2",
"filesize": 349257728,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAZ_VM64_KVM-v7.0.9-build0489-FORTINET.out.kvm.qcow2",
"version": "7.0.9",
"md5sum": "3f69c9bc4fa7776476edf0ce9728ebd7",
"filesize": 347889664,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAZ_VM64_KVM-v7.0.6-build0372-FORTINET.out.kvm.qcow2",
"version": "7.0.6",
@@ -56,6 +92,20 @@
"filesize": 334184448,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAZ_VM64_KVM-v6.4.14-build2660-FORTINET.out.kvm.qcow2",
"version": "6.4.14",
"md5sum": "1629d76776c9d625faee0304b5840c02",
"filesize": 300683264,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAZ_VM64_KVM-v6.4.12-build2610-FORTINET.out.kvm.qcow2",
"version": "6.4.12",
"md5sum": "b9e164c2d4e778348a6a7107d375abf3",
"filesize": 300691456,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FAZ_VM64_KVM-v6-build2288-FORTINET.out.kvm.qcow2",
"version": "6.4.5",
@@ -206,6 +256,27 @@
}
],
"versions": [
{
"name": "7.4.2",
"images": {
"hda_disk_image": "FAZ_VM64_KVM-v7.4.2-build2397-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.4.1",
"images": {
"hda_disk_image": "FAZ_VM64_KVM-v7.4.1-build2308-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.4",
"images": {
"hda_disk_image": "FAZ_VM64_KVM-v7.2.4-build1460-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.2",
"images": {
@@ -220,6 +291,20 @@
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.11",
"images": {
"hda_disk_image": "FAZ_VM64_KVM-v7.0.11-build0595-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.9",
"images": {
"hda_disk_image": "FAZ_VM64_KVM-v7.0.9-build0489-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.6",
"images": {
@@ -234,6 +319,20 @@
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.14",
"images": {
"hda_disk_image": "FAZ_VM64_KVM-v6.4.14-build2660-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.12",
"images": {
"hda_disk_image": "FAZ_VM64_KVM-v6.4.12-build2610-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.5",
"images": {
+129 -3
View File
@@ -11,15 +11,15 @@
"product_url": "http://www.fortinet.com/products/fortigate/virtual-appliances.html",
"registry_version": 4,
"status": "stable",
"maintainer": "GNS3 Team",
"maintainer_email": "developers@gns3.net",
"maintainer": "Ean Towne",
"maintainer_email": "ean.fortinet@gmail.com",
"usage": "Default username is admin, no password is set.\n\n- FortiGate version 7.0.0 and above require 2GB RAM.\n\n- FortiGate versions higher than 7.2.0 trial license is VERY restrictive, not recommended for use.",
"symbol": "fortinet.svg",
"port_name_format": "Port{port1}",
"qemu": {
"adapter_type": "e1000",
"adapters": 10,
"ram": 1024,
"ram": 2048,
"hda_disk_interface": "virtio",
"hdb_disk_interface": "virtio",
"arch": "x86_64",
@@ -28,6 +28,34 @@
"kvm": "allow"
},
"images": [
{
"filename": "FGT_VM64_KVM-v7.4.3.F-build2573-FORTINET.out.kvm.qcow2",
"version": "7.4.3",
"md5sum": "e7517095c91dce1a76a9bcf114b5fa15",
"filesize": 100728832,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v7.4.1.F-build2463-FORTINET.out.kvm.qcow2",
"version": "7.4.1",
"md5sum": "362a2f3d4ca842aaabd87191d4446584",
"filesize": 116064256,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v7.2.7.M-build1577-FORTINET.out.kvm.qcow2",
"version": "7.2.7",
"md5sum": "752b56844e464b0b135e57f72681c288",
"filesize": 102760448,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v7.2.6.F-build1575-FORTINET.out.kvm.qcow2",
"version": "7.2.6",
"md5sum": "b5ef3c844abb4947f98b88ae0048660b",
"filesize": 103022592,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v7.2.4.F-build1396-FORTINET.out.kvm.qcow2",
"version": "7.2.4",
@@ -49,6 +77,27 @@
"filesize": 86704128,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v7.0.14.M-build0601-FORTINET.out.kvm.qcow2",
"version": "7.0.14",
"md5sum": "20c855889e1117902bcf448b30746d30",
"filesize": 77398016,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v7.0.13.M-build0566-FORTINET.out.kvm.qcow2",
"version": "7.0.13",
"md5sum": "47a4bab29407153a635c54b64d6a226e",
"filesize": 89325568,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v7.0.12.M-build0523-FORTINET.out.kvm.qcow2",
"version": "7.0.12",
"md5sum": "7cd2452dde489c80f48c40a7f8a48c8e",
"filesize": 88997888,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v7.0.10.M-build0450-FORTINET.out.kvm.qcow2",
"version": "7.0.10",
@@ -63,6 +112,20 @@
"filesize": 77135872,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v6.4.15.M-build2095-FORTINET.out.kvm.qcow2",
"version": "6.4.15",
"md5sum": "a0306a3905877de654dab7e1bb67089e",
"filesize": 81592320,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v6.4.14.M-build2093-FORTINET.out.kvm.qcow2",
"version": "6.4.14",
"md5sum": "5758340f9d3e1a03139176ab46e63e8d",
"filesize": 81461248,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FGT_VM64_KVM-v6.4.12.M-build2060-FORTINET.out.kvm.qcow2",
"version": "6.4.12",
@@ -304,6 +367,34 @@
}
],
"versions": [
{
"name": "7.4.3",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v7.4.3.F-build2573-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.4.1",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v7.4.1.F-build2463-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.7",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v7.2.7.M-build1577-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.6",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v7.2.6.F-build1575-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.4",
"images": {
@@ -325,6 +416,27 @@
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.14",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v7.0.14.M-build0601-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.13",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v7.0.13.M-build0566-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.12",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v7.0.12.M-build0523-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.10",
"images": {
@@ -339,6 +451,20 @@
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.15",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v6.4.15.M-build2095-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.14",
"images": {
"hda_disk_image": "FGT_VM64_KVM-v6.4.14.M-build2093-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.12",
"images": {
+103 -4
View File
@@ -11,15 +11,16 @@
"product_url": "http://www.fortinet.com/products/fortimanager/virtual-security-management.html",
"registry_version": 4,
"status": "stable",
"maintainer": "GNS3 Team",
"maintainer_email": "developers@gns3.net",
"usage": "Default username is admin, no password is set.\n\n- Versions 7.0 and higher require:\n--RAM: 8192 MB\n--CPU:4",
"maintainer": "Ean Towne",
"maintainer_email": "ean.fortinet@gmail.com",
"usage": "Default username is admin, no password is set.\n\n- Versions lower than 7.0.x require less CPU/RAM\n7.4.x may require 16GB RAM.",
"symbol": "fortinet.svg",
"port_name_format": "Port{port1}",
"qemu": {
"adapter_type": "virtio-net-pci",
"adapters": 4,
"ram": 2048,
"ram": 8192,
"cpus": 4,
"hda_disk_interface": "virtio",
"hdb_disk_interface": "virtio",
"arch": "x86_64",
@@ -28,6 +29,27 @@
"kvm": "allow"
},
"images": [
{
"filename": "FMG_VM64_KVM-v7.4.2-build2397-FORTINET.out.kvm.qcow2",
"version": "7.4.2",
"md5sum": "36371fbf06210ded57c00b2ff290f2c5",
"filesize": 322514944,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.4.1-build2308-FORTINET.out.kvm.qcow2",
"version": "7.4.1",
"md5sum": "e542cc8f2d8f46e9c32b783bf31bef39",
"filesize": 309387264,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.2.4-build1460-FORTINET.out.kvm.qcow2",
"version": "7.2.4",
"md5sum": "98fa9830d9ecb5911a703d03b80026b6",
"filesize": 261992448,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.2.2-build1334-FORTINET.out.kvm.qcow2",
"version": "7.2.2",
@@ -42,6 +64,20 @@
"filesize": 242814976,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.0.11-build0595-FORTINET.out.kvm.qcow2",
"version": "7.0.11",
"md5sum": "7b166222136e26190159f37cccbaab6e",
"filesize": 249360384,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.0.9-build0489-FORTINET.out.kvm.qcow2",
"version": "7.0.9",
"md5sum": "dbeb6a79b6e421000573dbbbdb50b8b5",
"filesize": 247955456,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v7.0.6-build0372-FORTINET.out.kvm.qcow2",
"version": "7.0.6",
@@ -56,6 +92,20 @@
"filesize": 237535232,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6.4.14-build2660-FORTINET.out.kvm.qcow2",
"version": "6.4.14",
"md5sum": "0fe56e363b166c07b710bde795e36049",
"filesize": 219430912,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6.4.12-build2610-FORTINET.out.kvm.qcow2",
"version": "6.4.12",
"md5sum": "36c0dc531d921e5f1e1e09b030f7c813",
"filesize": 219455488,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{
"filename": "FMG_VM64_KVM-v6-build2288-FORTINET.out.kvm.qcow2",
"version": "6.4.5",
@@ -206,6 +256,27 @@
}
],
"versions": [
{
"name": "7.4.2",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.4.2-build2397-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.4.1",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.4.1-build2308-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.4",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.2.4-build1460-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.2.2",
"images": {
@@ -220,6 +291,20 @@
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.11",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.0.11-build0595-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.9",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v7.0.9-build0489-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "7.0.6",
"images": {
@@ -234,6 +319,20 @@
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.14",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v6.4.14-build2660-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.12",
"images": {
"hda_disk_image": "FMG_VM64_KVM-v6.4.12-build2610-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{
"name": "6.4.5",
"images": {
+51 -2
View File
@@ -7,16 +7,65 @@
"vendor_url": "https://www.huawei.com",
"product_name": "HuaWei NE40E",
"product_url": "https://e.huawei.com/en/products/enterprise-networking/routers/ne/ne40e",
"registry_version": 4,
"registry_version": 6,
"status": "experimental",
"availability": "service-contract",
"maintainer": "none",
"maintainer_email": "",
"first_port_name": "eth0",
"port_name_format": "Ethernet1/0/{0}",
"qemu": {
"adapter_type": "e1000",
"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,
"cpus": 2,
"hda_disk_interface": "ide",
@@ -8,7 +8,7 @@
"documentation_url": "http://wiki.mikrotik.com/wiki/Manual:CHR",
"product_name": "MikroTik RouterBOARD 1100AHx4 Dude Edition",
"product_url": "http://www.mikrotik.com/download",
"registry_version": 5,
"registry_version": 4,
"status": "stable",
"maintainer": "Azorian Solutions",
"maintainer_email": "help@azorian.solutions",
+1 -1
View File
@@ -8,7 +8,7 @@
"documentation_url": "http://wiki.mikrotik.com/wiki/Manual:CHR",
"product_name": "MikroTik RouterBOARD 450G",
"product_url": "http://www.mikrotik.com/download",
"registry_version": 5,
"registry_version": 4,
"status": "stable",
"maintainer": "Azorian Solutions",
"maintainer_email": "help@azorian.solutions",
@@ -8,7 +8,7 @@
"documentation_url": "http://wiki.mikrotik.com/wiki/Manual:CHR",
"product_name": "MikroTik RouterBOARD 450Gx4",
"product_url": "http://www.mikrotik.com/download",
"registry_version": 5,
"registry_version": 4,
"status": "stable",
"maintainer": "Azorian Solutions",
"maintainer_email": "help@azorian.solutions",
+13
View File
@@ -30,6 +30,13 @@
"options": "-vga std -usbdevice tablet"
},
"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",
"version": "1.2.0",
@@ -46,6 +53,12 @@
}
],
"versions": [
{
"name": "1.3.0",
"images": {
"hda_disk_image": "ostinatostd-1.3.0-1.qcow2"
}
},
{
"name": "1.2.0",
"images": {
+17 -3
View File
@@ -11,9 +11,9 @@
"registry_version": 4,
"status": "stable",
"availability": "service-contract",
"maintainer": "Neyder Achahuanco",
"maintainer_email": "neyder@neyder.net",
"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",
"maintainer": "Da-Geek",
"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.3/x86_64/product-software attach/customize rhel-cloud-init.iso and start.\nusername: cloud-user\npassword: redhat",
"qemu": {
"adapter_type": "virtio-net-pci",
"adapters": 1,
@@ -26,6 +26,13 @@
"options": "-cpu host -nographic"
},
"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",
"version": "9.2",
@@ -112,6 +119,13 @@
}
],
"versions": [
{
"name": "9.3",
"images": {
"hda_disk_image": "rhel-9.3-x86_64-kvm.qcow2",
"cdrom_image": "rhel-cloud-init.iso"
}
},
{
"name": "9.2",
"images": {
+30
View File
@@ -26,6 +26,14 @@
"options": "-nographic -cpu host"
},
"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",
"version": "9.2",
@@ -34,6 +42,14 @@
"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"
},
{
"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",
"version": "8.8",
@@ -52,6 +68,13 @@
}
],
"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",
"images": {
@@ -59,6 +82,13 @@
"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",
"images": {
+5 -5
View File
@@ -28,12 +28,12 @@
},
"images": [
{
"filename": "ubuntu-23.04-server-cloudimg-arm64.img",
"filename": "ubuntu-23.04-server-cloudimg-amd64.img",
"version": "Ubuntu 23.04 (Lunar Lobster)",
"md5sum": "35fa3b31b65717af6f0520a769aac8c0",
"filesize": 786432000,
"md5sum": "369e3b1f68416c39245a8014172406dd",
"filesize": 756678656,
"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",
@@ -72,7 +72,7 @@
{
"name": "Ubuntu 23.04 (Lunar Lobster)",
"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"
}
},
+3
View File
@@ -656,6 +656,9 @@ class BaseNode:
"""
path = self._manager.config.get_section_config("Server").get("ubridge_path", "ubridge")
if sys.platform.startswith("win") and hasattr(sys, "frozen"):
ubridge_dir = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(sys.executable)), "ubridge"))
os.environ["PATH"] = os.pathsep.join(ubridge_dir) + os.pathsep + os.environ.get("PATH", "")
path = shutil.which(path)
return path
+61 -1
View File
@@ -19,11 +19,15 @@
Docker server module.
"""
import os
import sys
import json
import asyncio
import logging
import aiohttp
import shutil
import platformdirs
from gns3server.utils import parse_version
from gns3server.utils.asyncio import locking
from gns3server.compute.base_manager import BaseManager
@@ -55,6 +59,62 @@ class Docker(BaseManager):
self._session = None
self._api_version = DOCKER_MINIMUM_API_VERSION
@staticmethod
async def install_busybox(dst_dir):
dst_busybox = os.path.join(dst_dir, "bin", "busybox")
if os.path.isfile(dst_busybox):
return
for busybox_exec in ("busybox-static", "busybox.static", "busybox"):
busybox_path = shutil.which(busybox_exec)
if busybox_path:
try:
# check that busybox is statically linked
# (dynamically linked busybox will fail to run in a container)
proc = await asyncio.create_subprocess_exec(
"ldd",
busybox_path,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.DEVNULL
)
stdout, _ = await proc.communicate()
if proc.returncode == 1:
# ldd returns 1 if the file is not a dynamic executable
log.info(f"Installing busybox from '{busybox_path}' to '{dst_busybox}'")
shutil.copy2(busybox_path, dst_busybox, follow_symlinks=True)
return
else:
log.warning(f"Busybox '{busybox_path}' is dynamically linked\n"
f"{stdout.decode('utf-8', errors='ignore').strip()}")
except OSError as e:
raise DockerError(f"Could not install busybox: {e}")
raise DockerError("No busybox executable could be found")
@staticmethod
def resources_path():
"""
Get the Docker resources storage directory
"""
appname = vendor = "GNS3"
docker_resources_dir = os.path.join(platformdirs.user_data_dir(appname, vendor, roaming=True), "docker", "resources")
os.makedirs(docker_resources_dir, exist_ok=True)
return docker_resources_dir
async def install_resources(self):
"""
Copy the necessary resources to a writable location and install busybox
"""
try:
dst_path = self.resources_path()
log.info(f"Installing Docker resources in '{dst_path}'")
from gns3server.controller import Controller
Controller.instance().install_resource_files(dst_path, "compute/docker/resources")
await self.install_busybox(dst_path)
except OSError as e:
raise DockerError(f"Could not install Docker resources to {dst_path}: {e}")
async def _check_connection(self):
if not self._connected:
@@ -135,7 +195,7 @@ class Docker(BaseManager):
timeout = 60 * 60 * 24 * 31 # One month timeout
if path == 'version':
url = "http://docker/v1.12/" + path # API of docker v1.0
url = "http://docker/v1.24/" + path
else:
url = "http://docker/v" + DOCKER_MINIMUM_API_VERSION + "/" + path
try:
+9 -4
View File
@@ -242,10 +242,13 @@ class DockerVM(BaseNode):
:returns: Return the path that we need to map to local folders
"""
resources = get_resource("compute/docker/resources")
if not os.path.exists(resources):
raise DockerError("{} is missing can't start Docker containers".format(resources))
binds = ["{}:/gns3:ro".format(resources)]
try:
resources_path = self.manager.resources_path()
except OSError as e:
raise DockerError(f"Cannot access resources: {e}")
log.info(f'Mount resources from "{resources_path}"')
binds = ["{}:/gns3:ro".format(resources_path)]
# We mount our own etc/network
try:
@@ -460,6 +463,8 @@ class DockerVM(BaseNode):
Starts this Docker container.
"""
await self.manager.install_resources()
try:
state = await self._get_container_state()
except DockerHttp404Error:
+3
View File
@@ -252,6 +252,9 @@ class Dynamips(BaseManager):
# look for Dynamips
dynamips_path = self.config.get_section_config("Dynamips").get("dynamips_path", "dynamips")
if not os.path.isabs(dynamips_path):
if sys.platform.startswith("win") and hasattr(sys, "frozen"):
dynamips_dir = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(sys.executable)), "dynamips"))
os.environ["PATH"] = os.pathsep.join(dynamips_dir) + os.pathsep + os.environ.get("PATH", "")
dynamips_path = shutil.which(dynamips_path)
if not dynamips_path:
+6 -1
View File
@@ -539,7 +539,12 @@ class IOUVM(BaseNode):
# create a symbolic link to the image to avoid IOU error "failed code signing checks"
# on newer images, see https://github.com/GNS3/gns3-server/issues/1484
try:
symlink = os.path.join(self.working_dir, os.path.basename(self.path))
iou_image_path = os.path.basename(self.path)
if len(iou_image_path) > 63:
# IOU file basename length must be <= 63 chars
iou_file_name, iou_file_ext = os.path.splitext(iou_image_path)
iou_image_path = iou_file_name[:63 - len(iou_file_ext)] + iou_file_ext
symlink = os.path.join(self.working_dir, iou_image_path)
if os.path.islink(symlink):
os.unlink(symlink)
os.symlink(self.path, symlink)
+10 -7
View File
@@ -16,12 +16,14 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import aiohttp
import asyncio
import psutil
import platform
from .project import Project
from ..config import Config
from uuid import UUID
import logging
log = logging.getLogger(__name__)
@@ -128,10 +130,11 @@ class ProjectManager:
:returns: boolean
"""
for project in self._projects.values():
for node in project.nodes:
if node == source_node:
continue
if node.hw_virtualization and node.__class__.__name__ != source_node.__class__.__name__:
return False
if Config.instance().get_section_config("Server").getboolean("hardware_virtualization_check", True):
for project in self._projects.values():
for node in project.nodes:
if node == source_node:
continue
if node.hw_virtualization and node.__class__.__name__ != source_node.__class__.__name__:
return False
return True
+13 -3
View File
@@ -26,6 +26,7 @@ import sys
import re
import subprocess
from ...utils import shlex_quote
from ...utils.asyncio import subprocess_check_output
from ...utils.get_resource import get_resource
from ..base_manager import BaseManager
@@ -159,13 +160,20 @@ class Qemu(BaseManager):
for arch in archs:
if f.endswith(arch) or f.endswith("{}.exe".format(arch)) or f.endswith("{}w.exe".format(arch)):
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})
else:
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})
except OSError:
continue
@@ -337,6 +345,8 @@ class Qemu(BaseManager):
command.append(path)
command.append("{}M".format(img_size))
command_string = " ".join(shlex_quote(s) for s in command)
log.info("Creating disk image with {}".format(command_string))
process = await asyncio.create_subprocess_exec(*command)
await process.wait()
except (OSError, subprocess.SubprocessError) as e:
+3
View File
@@ -2426,6 +2426,9 @@ class QemuVM(BaseNode):
command.extend(shlex.split(additional_options))
except ValueError as e:
raise QemuError("Invalid additional options: {} error {}".format(additional_options, 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
def __json__(self):
+3
View File
@@ -140,6 +140,9 @@ class VPCSVM(BaseNode):
vpcs_path = self._manager.config.get_section_config("VPCS").get("vpcs_path", "vpcs")
if not os.path.isabs(vpcs_path):
if sys.platform.startswith("win") and hasattr(sys, "frozen"):
vpcs_dir = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(sys.executable)), "vpcs"))
os.environ["PATH"] = os.pathsep.join(vpcs_dir) + os.pathsep + os.environ.get("PATH", "")
vpcs_path = shutil.which(vpcs_path)
return vpcs_path
@@ -13,7 +13,8 @@ logging console discriminator EXCESS
!
no ip icmp rate-limit unreachable
!
ip cef
! due to some bugs with IOU, try to change the following line to 'ip cef' if your routing does not work
no ip cef
no ip domain-lookup
!
!
@@ -12,7 +12,8 @@ no ip icmp rate-limit unreachable
!
!
!
ip cef
! due to some bugs with IOU, try to change the following line to 'ip cef' if your routing does not work
no ip cef
no ip domain-lookup
!
!
+3
View File
@@ -300,6 +300,9 @@ class Controller:
if entry.is_file() and not os.path.exists(full_path):
log.debug(f'Installing {resource_name} resource file "{entry.name}" to "{full_path}"')
shutil.copy(str(entry), os.path.join(dst_path, entry.name))
elif entry.is_dir():
os.makedirs(full_path, exist_ok=True)
Controller.install_resource_files(full_path, os.path.join(resource_name, entry.name))
def _install_base_configs(self):
"""
+5
View File
@@ -83,6 +83,11 @@ async def export_project(zstream, project, temporary_dir, include_images=False,
continue
_patch_mtime(path)
zstream.write(path, os.path.relpath(path, project._path))
# save empty directories
for directory in dirs:
path = os.path.join(root, directory)
if not os.listdir(path):
zstream.write(path, os.path.relpath(path, project._path))
except FileNotFoundError as e:
log.warning("Cannot export local file: {}".format(e))
continue
+19 -5
View File
@@ -130,16 +130,27 @@ class Project:
self._iou_id_lock = asyncio.Lock()
log.debug('Project "{name}" [{id}] loaded'.format(name=self.name, id=self._id))
self.emit_controller_notification("project.created", self.__json__())
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 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):
"""
@@ -154,7 +165,7 @@ class Project:
# We send notif only if object has changed
if old_json != self.__json__():
self.emit_notification("project.updated", self.__json__())
self.emit_controller_notification("project.updated", self.__json__())
self.dump()
# update on computes
@@ -803,7 +814,8 @@ class Project:
self._clean_pictures()
self._status = "closed"
if not ignore_notification:
self.emit_notification("project.closed", self.__json__())
self.emit_controller_notification("project.closed", self.__json__())
self.reset()
self._closing = False
@@ -857,6 +869,7 @@ class Project:
shutil.rmtree(self.path)
except OSError as e:
raise aiohttp.web.HTTPConflict(text="Cannot delete project directory {}: {}".format(self.path, str(e)))
self.emit_controller_notification("project.deleted", self.__json__())
async def delete_on_computes(self):
"""
@@ -976,7 +989,7 @@ class Project:
await self.add_drawing(dump=False, **drawing_data)
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:
for compute in list(self._project_created_on_compute):
try:
@@ -1001,6 +1014,7 @@ class Project:
pass
self._loading = False
self.emit_controller_notification("project.opened", self.__json__())
# Should we start the nodes when project is open
if self._auto_start:
# Start all in the background without waiting for completion
+1 -1
View File
@@ -57,7 +57,7 @@ class CrashReport:
Report crash to a third party service
"""
DSN = "https://8dcaf668c2f31af6028fb4130bf2f58e@o19455.ingest.sentry.io/38482"
DSN = "https://535981c5fae1a87b7e8d993590c07c27@o19455.ingest.sentry.io/38482"
_instance = None
def __init__(self):
@@ -487,11 +487,18 @@ class NodeHandler:
except ValueError:
pass
ws_console_compute_url = "ws://{compute_host}:{compute_port}/v2/compute/projects/{project_id}/{node_type}/nodes/{node_id}/console/ws".format(compute_host=compute_host,
compute_port=compute.port,
project_id=project.id,
node_type=node.node_type,
node_id=node.id)
ws_protocol = "ws"
if request.scheme == "https":
ws_protocol = "wss"
ws_console_compute_url = "{protocol}://{compute_host}:{compute_port}/v2/compute/projects/{project_id}/{node_type}/nodes/{node_id}/console/ws".format(
protocol=ws_protocol,
compute_host=compute_host,
compute_port=compute.port,
project_id=project.id,
node_type=node.node_type,
node_id=node.id
)
async def ws_forward(ws_client):
async for msg in ws:
@@ -504,7 +511,7 @@ class NodeHandler:
try:
async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=None, force_close=True)) as session:
async with session.ws_connect(ws_console_compute_url) as ws_client:
async with session.ws_connect(ws_console_compute_url, ssl=False) as ws_client:
asyncio.ensure_future(ws_forward(ws_client))
async for msg in ws_client:
if msg.type == aiohttp.WSMsgType.TEXT:
@@ -515,6 +522,8 @@ class NodeHandler:
break
except ConnectionResetError:
log.info("Websocket console connection with compute disconnected")
except aiohttp.ClientError as e:
log.error("Websocket console connection with compute failed: {}".format(e))
finally:
if not ws.closed:
await ws.close()
+4
View File
@@ -31,6 +31,7 @@ import gns3server.utils.get_resource
import os
import sys
import types
import multiprocessing
# To avoid strange bug later we switch the event loop before any other operation
if sys.platform.startswith("win"):
@@ -79,6 +80,9 @@ def main():
if not sys.platform.startswith("win"):
if "--daemon" in sys.argv:
daemonize()
else:
multiprocessing.freeze_support()
from gns3server.run import run
run()
+3 -3
View File
@@ -235,9 +235,9 @@ def run():
return
log.info("HTTP authentication is enabled with username '{}'".format(user))
# we only support Python 3 version >= 3.6
if sys.version_info < (3, 6, 0):
raise SystemExit("Python 3.6 or higher is required")
# we only support Python 3 version >= 3.7
if sys.version_info < (3, 7, 0):
raise SystemExit("Python 3.7 or higher is required")
user_log.info("Running with Python {major}.{minor}.{micro} and has PID {pid}".format(major=sys.version_info[0], minor=sys.version_info[1],
micro=sys.version_info[2], pid=os.getpid()))
+26 -46
View File
@@ -17,28 +17,30 @@
import copy
ETHERNET_HUB_PORT_SCHEMA = {
"description": "Ethernet port",
"properties": {
"name": {
"description": "Port name",
"type": "string",
"minLength": 1,
},
"port_number": {
"description": "Port number",
"type": "integer",
"minimum": 0
},
},
"required": ["name", "port_number"],
"additionalProperties": False
}
ETHERNET_HUB_CREATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to create a new Ethernet hub instance",
"type": "object",
"definitions": {
"EthernetHubPort": {
"description": "Ethernet port",
"properties": {
"name": {
"description": "Port name",
"type": "string",
"minLength": 1,
},
"port_number": {
"description": "Port number",
"type": "integer",
"minimum": 0
},
},
"required": ["name", "port_number"],
"additionalProperties": False
},
"EthernetHubPort": ETHERNET_HUB_PORT_SCHEMA
},
"properties": {
"name": {
@@ -57,12 +59,9 @@ ETHERNET_HUB_CREATE_SCHEMA = {
},
"ports_mapping": {
"type": "array",
"items": [
{"type": "object",
"oneOf": [
{"$ref": "#/definitions/EthernetHubPort"}
]},
]
"items": {
"$ref": "#/definitions/EthernetHubPort"
}
},
},
"additionalProperties": False,
@@ -74,23 +73,7 @@ ETHERNET_HUB_OBJECT_SCHEMA = {
"description": "Ethernet hub instance",
"type": "object",
"definitions": {
"EthernetHubPort": {
"description": "Ethernet port",
"properties": {
"name": {
"description": "Port name",
"type": "string",
"minLength": 1,
},
"port_number": {
"description": "Port number",
"type": "integer",
"minimum": 0
},
},
"required": ["name", "port_number"],
"additionalProperties": False
},
"EthernetHubPort": ETHERNET_HUB_PORT_SCHEMA
},
"properties": {
"name": {
@@ -114,12 +97,9 @@ ETHERNET_HUB_OBJECT_SCHEMA = {
},
"ports_mapping": {
"type": "array",
"items": [
{"type": "object",
"oneOf": [
{"$ref": "#/definitions/EthernetHubPort"}
]},
]
"items": {
"$ref": "#/definitions/EthernetHubPort"
}
},
"status": {
"description": "Node status",
+38 -70
View File
@@ -17,40 +17,42 @@
import copy
ETHERNET_SWITCH_PORT_SCHEMA = {
"description": "Ethernet switch port",
"properties": {
"name": {
"description": "Port name",
"type": "string",
"minLength": 1,
},
"port_number": {
"description": "Port number",
"type": "integer",
"minimum": 0
},
"type": {
"description": "Port type",
"enum": ["access", "dot1q", "qinq"],
},
"vlan": {"description": "VLAN number",
"type": "integer",
"minimum": 1
},
"ethertype": {
"description": "QinQ Ethertype",
"enum": ["", "0x8100", "0x88A8", "0x9100", "0x9200"],
},
},
"required": ["name", "port_number", "type"],
"additionalProperties": False
}
ETHERNET_SWITCH_CREATE_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to create a new Ethernet switch instance",
"type": "object",
"definitions": {
"EthernetSwitchPort": {
"description": "Ethernet port",
"properties": {
"name": {
"description": "Port name",
"type": "string",
"minLength": 1,
},
"port_number": {
"description": "Port number",
"type": "integer",
"minimum": 0
},
"type": {
"description": "Port type",
"enum": ["access", "dot1q", "qinq"],
},
"vlan": {"description": "VLAN number",
"type": "integer",
"minimum": 1
},
"ethertype": {
"description": "QinQ Ethertype",
"enum": ["", "0x8100", "0x88A8", "0x9100", "0x9200"],
},
},
"required": ["name", "port_number", "type"],
"additionalProperties": False
},
"EthernetSwitchPort": ETHERNET_SWITCH_PORT_SCHEMA
},
"properties": {
"name": {
@@ -79,12 +81,9 @@ ETHERNET_SWITCH_CREATE_SCHEMA = {
},
"ports_mapping": {
"type": "array",
"items": [
{"type": "object",
"oneOf": [
{"$ref": "#/definitions/EthernetSwitchPort"}
]},
]
"items": {
"$ref": "#/definitions/EthernetSwitchPort"
}
},
},
"additionalProperties": False,
@@ -96,35 +95,7 @@ ETHERNET_SWITCH_OBJECT_SCHEMA = {
"description": "Ethernet switch instance",
"type": "object",
"definitions": {
"EthernetSwitchPort": {
"description": "Ethernet port",
"properties": {
"name": {
"description": "Port name",
"type": "string",
"minLength": 1,
},
"port_number": {
"description": "Port number",
"type": "integer",
"minimum": 0
},
"type": {
"description": "Port type",
"enum": ["access", "dot1q", "qinq"],
},
"vlan": {"description": "VLAN number",
"type": "integer",
"minimum": 1
},
"ethertype": {
"description": "QinQ Ethertype",
"enum": ["", "0x8100", "0x88A8", "0x9100", "0x9200"],
},
},
"required": ["name", "port_number", "type"],
"additionalProperties": False
},
"EthernetSwitchPort": ETHERNET_SWITCH_PORT_SCHEMA
},
"properties": {
"name": {
@@ -148,12 +119,9 @@ ETHERNET_SWITCH_OBJECT_SCHEMA = {
},
"ports_mapping": {
"type": "array",
"items": [
{"type": "object",
"oneOf": [
{"$ref": "#/definitions/EthernetSwitchPort"}
]},
]
"items": {
"$ref": "#/definitions/EthernetSwitchPort"
}
},
"status": {
"description": "Node status",
+2 -2
View File
@@ -65,8 +65,8 @@ QEMU_TEMPLATE_PROPERTIES = {
"description": "QEMU adapter type",
"type": "string",
"enum": ["e1000", "e1000-82544gc", "e1000-82545em", "e1000e", "i82550", "i82551", "i82557a", "i82557b", "i82557c", "i82558a",
"i82558b", "i82559a", "i82559b", "i82559c", "i82559er", "i82562", "i82801", "ne2k_pci", "pcnet", "rocker", "rtl8139",
"virtio", "virtio-net-pci", "vmxnet3"],
"i82558b", "i82559a", "i82559b", "i82559c", "i82559er", "i82562", "i82801", "igb", "ne2k_pci", "pcnet", "rocker",
"rtl8139", "virtio", "virtio-net-pci", "vmxnet3"],
"default": "e1000"
},
"mac_address": {
@@ -1542,6 +1542,29 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ipaddr.js
MIT
Copyright (C) 2011-2017 whitequark <whitequark@whitequark.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
mdn-data
CC0-1.0
CC0 1.0 Universal
+1 -1
View File
@@ -46,6 +46,6 @@
gtag('config', 'G-5D6FZL9923');
</script>
<script src="runtime.baa1121a4737aeb68bb7.js" defer></script><script src="polyfills-es5.865074f5cd9a121111a2.js" nomodule defer></script><script src="polyfills.2f91a039d848e57ff02e.js" defer></script><script src="main.6b11a28a9dc4ce54a2ab.js" defer></script>
<script src="runtime.ecefb4ce510d1c218e7d.js" defer></script><script src="polyfills-es5.865074f5cd9a121111a2.js" nomodule defer></script><script src="polyfills.2f91a039d848e57ff02e.js" defer></script><script src="main.93bb4a803caf93e6752d.js" defer></script>
</body></html>
@@ -1 +0,0 @@
(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
@@ -0,0 +1 @@
(self.webpackChunkgns3_web_ui=self.webpackChunkgns3_web_ui||[]).push([[179],{98255:function(ue){function q(f){return Promise.resolve().then(function(){var B=new Error("Cannot find module '"+f+"'");throw B.code="MODULE_NOT_FOUND",B})}q.keys=function(){return[]},q.resolve=q,q.id=98255,ue.exports=q},82908:function(ue){ue.exports=function(f,B){(null==B||B>f.length)&&(B=f.length);for(var U=0,V=new Array(B);U<B;U++)V[U]=f[U];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,B){var U=null==f?null:"undefined"!=typeof Symbol&&f[Symbol.iterator]||f["@@iterator"];if(null!=U){var N,b,V=[],Z=!0,w=!1;try{for(U=U.call(f);!(Z=(N=U.next()).done)&&(V.push(N.value),!B||V.length!==B);Z=!0);}catch(_){w=!0,b=_}finally{try{!Z&&null!=U.return&&U.return()}finally{if(w)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 B=f(36457),U=f(35036),V=f(54850),Z=f(13969);ue.exports=function(N,b){return B(N)||U(N,b)||V(N,b)||Z()},ue.exports.default=ue.exports,ue.exports.__esModule=!0},54850:function(ue,q,f){var B=f(82908);ue.exports=function(V,Z){if(V){if("string"==typeof V)return B(V,Z);var w=Object.prototype.toString.call(V).slice(8,-1);if("Object"===w&&V.constructor&&(w=V.constructor.name),"Map"===w||"Set"===w)return Array.from(V);if("Arguments"===w||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(w))return B(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 U},mG:function(){return _},Jh:function(){return I},ev:function(){return R}});var B=function($,ae){return(B=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 U($,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=$}B($,ae),$.prototype=null===ae?Object.create(ae):(se.prototype=ae.prototype,new se)}function _($,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 R($,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 w},_j:function(){return V},LC:function(){return Z},ZN:function(){return O},jt:function(){return b},pV:function(){return T},F4:function(){return S},IO:function(){return k},vP:function(){return I},SB:function(){return A},oB:function(){return D},eR:function(){return v},X$:function(){return N},ZE:function(){return F},k1:function(){return z}});var B=f(14105),U=f(18967),V=function K(){(0,U.Z)(this,K)},Z=function K(){(0,U.Z)(this,K)},w="*";function N(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 +0,0 @@
!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](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))}()}();
@@ -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))}()}();
+16 -3
View File
@@ -190,6 +190,11 @@ class AsyncioTelnetServer:
sock = network_writer.get_extra_info("socket")
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
# 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
@@ -292,9 +297,17 @@ class AsyncioTelnetServer:
reader_read = await self._get_reader(network_reader)
# Replicate the output on all clients
for connection in self._connections.values():
connection.writer.write(data)
await connection.writer.drain()
for connection_key in list(self._connections.keys()):
client_info = connection_key.get_extra_info("socket").getpeername()
connection = self._connections[connection_key]
try:
connection.writer.write(data)
await asyncio.wait_for(connection.writer.drain(), timeout=10)
except:
log.debug(f"Timeout while sending data to client: {client_info}, closing and removing from connection table.")
connection.close()
del self._connections[connection_key]
async def _read(self, cmd, buffer, location, reader):
""" Reads next op from the buffer or reader"""
+2 -2
View File
@@ -23,8 +23,8 @@
# or negative for a release candidate or beta (after the base version
# number has been incremented)
__version__ = "2.2.44.dev1"
__version_info__ = (2, 2, 44, 99)
__version__ = "2.2.46"
__version_info__ = (2, 2, 46, 0)
if "dev" in __version__:
try:
+30 -8
View File
@@ -38,7 +38,7 @@ from .route import Route
from ..config import Config
from ..compute import MODULES
from ..compute.port_manager import PortManager
from ..compute.qemu import Qemu
from ..utils.images import list_images
from ..controller import Controller
# do not delete this import
@@ -87,6 +87,8 @@ class WebServer:
except (RuntimeError, OSError, asyncio.CancelledError) as e:
log.critical("Could not start the server: {}".format(e))
return False
except KeyboardInterrupt:
return False
return True
async def reload_server(self):
@@ -230,16 +232,34 @@ class WebServer:
atexit.register(close_asyncio_loop)
async def _compute_image_checksums(self):
"""
Compute image checksums.
"""
if sys.platform.startswith("darwin") and hasattr(sys, "frozen"):
# do not compute on macOS because errors
return
loop = asyncio.get_event_loop()
import concurrent.futures
with concurrent.futures.ProcessPoolExecutor(max_workers=1) as pool:
try:
log.info("Computing image checksums...")
await loop.run_in_executor(pool, list_images, "qemu")
log.info("Finished computing image checksums")
except OSError as e:
log.warning("Could not compute image checksums: {}".format(e))
async def _on_startup(self, *args):
"""
Called when the HTTP server start
"""
await Controller.instance().start()
# Because with a large image collection
# without md5sum already computed we start the
# computing with server start
asyncio.ensure_future(Qemu.instance().list_images())
# Start computing checksums now because it can take a long time
# for a large image collection
await self._compute_image_checksums()
def run(self):
"""
@@ -291,13 +311,13 @@ class WebServer:
# Background task started with the server
self._app.on_startup.append(self._on_startup)
resource_options = aiohttp_cors.ResourceOptions(expose_headers="*", allow_headers="*", max_age=0)
resource_options = aiohttp_cors.ResourceOptions(allow_credentials=True, expose_headers="*", allow_headers="*", max_age=0)
# Allow CORS for this domains
cors = aiohttp_cors.setup(self._app, defaults={
# Default web server for web gui dev
"http://127.0.0.1:8080": resource_options,
"http://localhost:8080": resource_options,
"http://127.0.0.1:3080": resource_options,
"http://localhost:3080": resource_options,
"http://127.0.0.1:4200": resource_options,
"http://localhost:4200": resource_options,
"http://gns3.github.io": resource_options,
@@ -330,6 +350,8 @@ class WebServer:
try:
self._loop.run_forever()
except ConnectionResetError:
log.warning("Connection reset by peer")
except TypeError as e:
# This is to ignore an asyncio.windows_events exception
# on Windows when the process gets the SIGBREAK signal
+8 -4
View File
@@ -1,5 +1,9 @@
build:
image: latest
version: 2
python:
version: 3.6
build:
os: "ubuntu-22.04"
tools:
python: "3.12"
sphinx:
configuration: docs/conf.py
+10 -13
View File
@@ -1,18 +1,15 @@
jsonschema>=4.17.3,<4.18; python_version >= '3.7' # v4.17.3 is the last version to support Python 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.5,<3.9
jsonschema>=4.17.3,<4.18 # v4.17.3 is the last version to support Python 3.7
aiohttp>=3.8.6,<3.9; python_version == '3.7' # v3.8.6 is the last version to support Python 3.7
aiohttp>=3.9.3,<3.10; python_version > '3.7'
aiohttp-cors>=0.7.0,<0.8
aiofiles>=23.2.1,<23.3; 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.32.0,<1.33
psutil==5.9.6
async-timeout>=4.0.2,<4.1
distro>=1.8.0
aiofiles>=23.2.1,<23.3
Jinja2>=3.1.3,<3.2
sentry-sdk==1.39.2,<1.40
psutil==5.9.8
async-timeout>=4.0.3,<4.1
distro>=1.9.0
py-cpuinfo>=9.0.0,<10.0
platformdirs>=2.4.0
importlib-resources>=1.3; python_version < '3.9'
truststore>=0.8.0; python_version >= '3.10'
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
setuptools>=60.8.1
+40
View File
@@ -0,0 +1,40 @@
#!/bin/bash
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Bash shell script for generating self-signed certs.
# The certificate is automatically put in your GNS3 config
DST_DIR="$HOME/.config/GNS3/ssl"
OLD_DIR=`pwd`
fail_if_error() {
[ $1 != 0 ] && {
unset PASSPHRASE
cd $OLD_DIR
exit 10
}
}
mkdir -p $DST_DIR
fail_if_error $?
cd $DST_DIR
SUBJ="/C=US/ST=Texas/O=GNS3SELF/localityName=Austin/commonName=localhost/organizationalUnitName=GNS3Server/emailAddress=gns3cert@gns3.com"
openssl req -nodes -new -x509 -keyout server.key -out server.cert -subj "$SUBJ"
+8 -3
View File
@@ -163,9 +163,9 @@ log "Install GNS3 packages"
apt-get install -y gns3-server
log "Create user GNS3 with /opt/gns3 as home directory"
if [ ! -d "/opt/gns3/" ]
if [ ! -d "/opt/gns3" ]
then
useradd -m -d /opt/gns3/ gns3
useradd -m -d /opt/gns3 gns3
fi
@@ -304,6 +304,11 @@ log "GNS3 installed with success"
if [ $WELCOME_SETUP == 1 ]
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 python3-pip
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()'
cd /opt/gns3
su gns3
fi
fi
+32 -12
View File
@@ -163,19 +163,38 @@ class Welcome_dialog:
def update(self, force=False):
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
release = self.get_release()
if release == "2.2":
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:
code, option = self.display.menu("Select an option",
choices=[("Upgrade GNS3", "Upgrades only the GNS3 pakage and dependences."),
("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
if release.endswith("dev"):
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))
else:
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)
if option == "Dist Upgrade":
if self.display.yesno("Reboot now?") == self.display.OK:
os.system("sudo reboot now")
def migrate(self):
@@ -438,7 +457,8 @@ Images and projects are located in /opt/gns3
self.display.clear()
if code == Dialog.OK:
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":
self.mode()
elif tag == "Restore":
+4 -27
View File
@@ -23,9 +23,9 @@ import subprocess
from setuptools import setup, find_packages
from setuptools.command.test import test as TestCommand
# we only support Python 3 version >= 3.5.3
if len(sys.argv) >= 2 and sys.argv[1] == "install" and sys.version_info < (3, 5, 3):
raise SystemExit("Python 3.5.3 or higher is required")
# we only support Python 3 version >= 3.7
if len(sys.argv) >= 2 and sys.argv[1] == "install" and sys.version_info < (3, 7):
raise SystemExit("Python 3.7 or higher is required")
class PyTest(TestCommand):
@@ -43,28 +43,6 @@ 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(
@@ -89,7 +67,7 @@ setup(
include_package_data=True,
zip_safe=False,
platforms="any",
python_requires='>=3.6.0',
python_requires='>=3.7',
setup_requires=["setuptools>=17.1"],
classifiers=[
"Development Status :: 5 - Production/Stable",
@@ -103,7 +81,6 @@ setup(
"Operating System :: Microsoft :: Windows",
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
+50
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 asyncio
import pytest
from unittest.mock import MagicMock, patch
@@ -200,3 +201,52 @@ async def test_docker_check_connection_docker_preferred_version_against_older(vm
vm._connected = False
await vm._check_connection()
assert vm._api_version == DOCKER_MINIMUM_API_VERSION
@pytest.mark.asyncio
async def test_install_busybox():
mock_process = MagicMock()
mock_process.returncode = 1 # means that busybox is not dynamically linked
mock_process.communicate = AsyncioMagicMock(return_value=(b"", b"not a dynamic executable"))
with patch("gns3server.compute.docker.os.path.isfile", return_value=False):
with patch("gns3server.compute.docker.shutil.which", return_value="/usr/bin/busybox"):
with asyncio_patch("gns3server.compute.docker.asyncio.create_subprocess_exec", return_value=mock_process) as create_subprocess_mock:
with patch("gns3server.compute.docker.shutil.copy2") as copy2_mock:
dst_dir = Docker.resources_path()
await Docker.install_busybox(dst_dir)
create_subprocess_mock.assert_called_with(
"ldd",
"/usr/bin/busybox",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.DEVNULL,
)
assert copy2_mock.called
@pytest.mark.asyncio
async def test_install_busybox_dynamic_linked():
mock_process = MagicMock()
mock_process.returncode = 0 # means that busybox is dynamically linked
mock_process.communicate = AsyncioMagicMock(return_value=(b"Dynamically linked library", b""))
with patch("os.path.isfile", return_value=False):
with patch("gns3server.compute.docker.shutil.which", return_value="/usr/bin/busybox"):
with asyncio_patch("gns3server.compute.docker.asyncio.create_subprocess_exec", return_value=mock_process):
with pytest.raises(DockerError) as e:
dst_dir = Docker.resources_path()
await Docker.install_busybox(dst_dir)
assert str(e.value) == "No busybox executable could be found"
@pytest.mark.asyncio
async def test_install_busybox_no_executables():
with patch("gns3server.compute.docker.os.path.isfile", return_value=False):
with patch("gns3server.compute.docker.shutil.which", return_value=None):
with pytest.raises(DockerError) as e:
dst_dir = Docker.resources_path()
await Docker.install_busybox(dst_dir)
assert str(e.value) == "No busybox executable could be found"
+43 -20
View File
@@ -25,10 +25,8 @@ from tests.utils import asyncio_patch, AsyncioMagicMock
from gns3server.ubridge.ubridge_error import UbridgeNamespaceError
from gns3server.compute.docker.docker_vm import DockerVM
from gns3server.compute.docker.docker_error import DockerError, DockerHttp404Error, DockerHttp304Error
from gns3server.compute.docker.docker_error import DockerError, DockerHttp404Error
from gns3server.compute.docker import Docker
from gns3server.utils.get_resource import get_resource
from unittest.mock import patch, MagicMock, call
@@ -101,7 +99,7 @@ async def test_create(compute_project, manager):
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network"))
],
"Privileged": True
@@ -139,7 +137,7 @@ async def test_create_with_tag(compute_project, manager):
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network"))
],
"Privileged": True
@@ -180,7 +178,7 @@ async def test_create_vnc(compute_project, manager):
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network")),
"/tmp/.X11-unix/X{0}:/tmp/.X11-unix/X{0}:ro".format(vm._display)
],
@@ -310,7 +308,7 @@ async def test_create_start_cmd(compute_project, manager):
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network"))
],
"Privileged": True
@@ -408,7 +406,7 @@ async def test_create_image_not_available(compute_project, manager):
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network"))
],
"Privileged": True
@@ -451,7 +449,7 @@ async def test_create_with_user(compute_project, manager):
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network"))
],
"Privileged": True
@@ -533,7 +531,7 @@ async def test_create_with_extra_volumes_duplicate_1_image(compute_project, mana
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network")),
"{}:/gns3volumes/vol/1".format(os.path.join(vm.working_dir, "vol", "1")),
],
@@ -572,7 +570,7 @@ async def test_create_with_extra_volumes_duplicate_2_user(compute_project, manag
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network")),
"{}:/gns3volumes/vol/1".format(os.path.join(vm.working_dir, "vol", "1")),
],
@@ -611,7 +609,7 @@ async def test_create_with_extra_volumes_duplicate_3_subdir(compute_project, man
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network")),
"{}:/gns3volumes/vol".format(os.path.join(vm.working_dir, "vol")),
],
@@ -650,7 +648,7 @@ async def test_create_with_extra_volumes_duplicate_4_backslash(compute_project,
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network")),
"{}:/gns3volumes/vol".format(os.path.join(vm.working_dir, "vol")),
],
@@ -689,7 +687,7 @@ async def test_create_with_extra_volumes_duplicate_5_subdir_issue_1595(compute_p
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc".format(os.path.join(vm.working_dir, "etc")),
],
"Privileged": True
@@ -727,7 +725,7 @@ async def test_create_with_extra_volumes_duplicate_6_subdir_issue_1595(compute_p
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc".format(os.path.join(vm.working_dir, "etc")),
],
"Privileged": True
@@ -771,7 +769,7 @@ async def test_create_with_extra_volumes(compute_project, manager):
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network")),
"{}:/gns3volumes/vol/1".format(os.path.join(vm.working_dir, "vol", "1")),
"{}:/gns3volumes/vol/2".format(os.path.join(vm.working_dir, "vol", "2")),
@@ -854,7 +852,7 @@ async def test_unpause(vm):
mock.assert_called_with("POST", "containers/e90e34656842/unpause")
async def test_start(vm, manager, free_console_port):
async def test_start(vm, manager, free_console_port, tmpdir):
assert vm.status != "started"
vm.adapters = 1
@@ -882,6 +880,31 @@ async def test_start(vm, manager, free_console_port):
assert vm.status == "started"
async def test_resources_installed(vm, manager, tmpdir):
assert vm.status != "started"
vm.adapters = 1
docker_resources_path = os.path.join(tmpdir, "docker", "resources")
os.makedirs(docker_resources_path, exist_ok=True)
manager.resources_path = MagicMock(return_value=docker_resources_path)
with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="stopped"):
with asyncio_patch("gns3server.compute.docker.Docker.query"):
with asyncio_patch("gns3server.compute.docker.DockerVM._start_ubridge"):
with asyncio_patch("gns3server.compute.docker.DockerVM._get_namespace", return_value=42):
with asyncio_patch("gns3server.compute.docker.DockerVM._add_ubridge_connection"):
with asyncio_patch("gns3server.compute.docker.DockerVM._start_console"):
await vm.start()
assert vm.status == "started"
assert os.path.exists(os.path.join(docker_resources_path, "init.sh"))
assert os.path.exists(os.path.join(docker_resources_path, "run-cmd.sh"))
assert os.path.exists(os.path.join(docker_resources_path, "bin", "busybox"))
assert os.path.exists(os.path.join(docker_resources_path, "bin", "udhcpc"))
assert os.path.exists(os.path.join(docker_resources_path, "etc", "udhcpc", "default.script"))
async def test_start_namespace_failed(vm, manager, free_console_port):
assert vm.status != "started"
@@ -996,7 +1019,7 @@ async def test_update(vm):
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network"))
],
"Privileged": True
@@ -1064,7 +1087,7 @@ async def test_update_running(vm):
{
"CapAdd": ["ALL"],
"Binds": [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network"))
],
"Privileged": True
@@ -1325,7 +1348,7 @@ async def test_mount_binds(vm):
dst = os.path.join(vm.working_dir, "test/experimental")
assert vm._mount_binds(image_infos) == [
"{}:/gns3:ro".format(get_resource("compute/docker/resources")),
"{}:/gns3:ro".format(Docker.resources_path()),
"{}:/gns3volumes/etc/network".format(os.path.join(vm.working_dir, "etc", "network")),
"{}:/gns3volumes{}".format(dst, "/test/experimental")
]
+13 -12
View File
@@ -208,18 +208,18 @@ async def test_termination_callback_error(vm, tmpdir):
async def test_reload(vm):
with asyncio_patch("gns3server.compute.qemu.QemuVM._control_vm") as mock:
with asyncio_patch("gns3server.compute.qemu.QemuVM._control_vm") as m:
await vm.reload()
assert mock.called_with("system_reset")
m.assert_called_with("system_reset")
async def test_suspend(vm):
async def test_suspend(vm, running_subprocess_mock):
control_vm_result = MagicMock()
control_vm_result.match.group.decode.return_value = "running"
with asyncio_patch("gns3server.compute.qemu.QemuVM._control_vm", return_value=control_vm_result) as mock:
await vm.suspend()
assert mock.called_with("system_reset")
vm._process = running_subprocess_mock
with asyncio_patch("gns3server.compute.qemu.QemuVM._get_vm_status", return_value="running"):
with asyncio_patch("gns3server.compute.qemu.QemuVM._control_vm") as m:
await vm.suspend()
m.assert_called_with("stop")
async def test_add_nio_binding_udp(vm):
@@ -490,14 +490,15 @@ def test_json(vm, compute_project):
assert json["project_id"] == compute_project.id
async def test_control_vm(vm):
async def test_control_vm(vm, running_subprocess_mock):
vm._process = MagicMock()
vm._process = running_subprocess_mock
vm._monitor = 4242
reader = MagicMock()
writer = MagicMock()
with asyncio_patch("asyncio.open_connection", return_value=(reader, writer)):
res = await vm._control_vm("test")
assert writer.write.called_with("test")
writer.write.assert_called_with(b"test\n")
assert res is None
@@ -514,7 +515,7 @@ async def test_control_vm_expect_text(vm, running_subprocess_mock):
vm._monitor = 4242
res = await vm._control_vm("test", [b"epic"])
assert writer.write.called_with("test")
writer.write.assert_called_with(b"test\n")
assert res == "epic product"
+3 -1
View File
@@ -213,7 +213,9 @@ async def test_compute_httpQuery_project(compute):
response = MagicMock()
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
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)
mock.assert_called_with("POST", "https://example.com:84/v2/compute/projects", data=json.dumps(project.__json__()), headers={'content-type': 'application/json'}, auth=None, chunked=None, timeout=20)
await compute.close()
+2
View File
@@ -111,6 +111,7 @@ async def test_export(tmpdir, project):
f.write("HELLO")
with open(os.path.join(path, "vm-1", "dynamips", "test_log.txt"), 'w+') as f:
f.write("LOG")
os.makedirs(os.path.join(path, "vm-1", "dynamips", "empty-dir"))
os.makedirs(os.path.join(path, "project-files", "snapshots"))
with open(os.path.join(path, "project-files", "snapshots", "test"), 'w+') as f:
f.write("WORLD")
@@ -127,6 +128,7 @@ async def test_export(tmpdir, project):
assert 'test.gns3' not in myzip.namelist()
assert 'project.gns3' in myzip.namelist()
assert 'vm-1/dynamips/empty-dir/' in myzip.namelist()
assert 'project-files/snapshots/test' not in myzip.namelist()
assert 'vm-1/dynamips/test_log.txt' not in myzip.namelist()
+50 -37
View File
@@ -47,15 +47,19 @@ async def node(controller, project):
async def test_affect_uuid():
p = Project(name="Test")
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'
with patch('gns3server.controller.project.Project.emit_controller_notification') as mock_notification:
p = Project(name="Test")
mock_notification.assert_called()
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'
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.__json__() == {
"name": "Test",
@@ -83,11 +87,11 @@ async def test_json():
async def test_update(controller):
project = Project(controller=controller, name="Hello")
project.emit_notification = MagicMock()
project.emit_controller_notification = MagicMock()
assert project.name == "Hello"
await project.update(name="World")
assert project.name == "World"
project.emit_notification.assert_any_call("project.updated", project.__json__())
project.emit_controller_notification.assert_any_call("project.updated", project.__json__())
async def test_update_on_compute(controller):
@@ -106,7 +110,9 @@ async def test_path(projects_dir):
directory = projects_dir
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 os.path.exists(os.path.join(directory, p.id))
@@ -124,23 +130,27 @@ def test_path_exist(tmpdir):
async def test_init_path(tmpdir):
p = Project(path=str(tmpdir), project_id=str(uuid4()), name="Test")
assert p.path == str(tmpdir)
with patch('gns3server.controller.project.Project.emit_controller_notification') as mock_notification:
p = Project(path=str(tmpdir), project_id=str(uuid4()), name="Test")
mock_notification.assert_called()
assert p.path == str(tmpdir)
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
async def test_changing_path_with_quote_not_allowed(tmpdir):
with pytest.raises(aiohttp.web.HTTPForbidden):
p = Project(project_id=str(uuid4()), name="Test")
p.path = str(tmpdir / "project\"53")
with patch('gns3server.controller.project.Project.emit_controller_notification'):
p = Project(project_id=str(uuid4()), name="Test")
p.path = str(tmpdir / "project\"53")
async def test_captures_directory(tmpdir):
p = Project(path=str(tmpdir / "capturestest"), name="Test")
assert p.captures_directory == str(tmpdir / "capturestest" / "project-files" / "captures")
assert os.path.exists(p.captures_directory)
with patch('gns3server.controller.project.Project.emit_controller_notification'):
p = Project(path=str(tmpdir / "capturestest"), name="Test")
assert p.captures_directory == str(tmpdir / "capturestest" / "project-files" / "captures")
assert os.path.exists(p.captures_directory)
async def test_add_node_local(controller):
@@ -649,36 +659,39 @@ async def test_dump(projects_dir):
directory = projects_dir
with patch("gns3server.utils.path.get_default_project_directory", return_value=directory):
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f', name="Test")
p.dump()
with open(os.path.join(directory, p.id, "Test.gns3")) as f:
content = f.read()
assert "00010203-0405-0607-0809-0a0b0c0d0e0f" in content
with patch('gns3server.controller.project.Project.emit_controller_notification'):
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f', name="Test")
p.dump()
with open(os.path.join(directory, p.id, "Test.gns3")) as f:
content = f.read()
assert "00010203-0405-0607-0809-0a0b0c0d0e0f" in content
async def test_open_close(controller):
project = Project(controller=controller, name="Test")
assert project.status == "opened"
await project.close()
project.start_all = AsyncioMagicMock()
await project.open()
assert not project.start_all.called
assert project.status == "opened"
project.emit_notification = MagicMock()
await project.close()
assert project.status == "closed"
project.emit_notification.assert_any_call("project.closed", project.__json__())
with patch('gns3server.controller.project.Project.emit_controller_notification'):
project = Project(controller=controller, name="Test")
assert project.status == "opened"
await project.close()
project.start_all = AsyncioMagicMock()
await project.open()
assert not project.start_all.called
assert project.status == "opened"
project.emit_controller_notification = MagicMock()
await project.close()
assert project.status == "closed"
project.emit_controller_notification.assert_any_call("project.closed", project.__json__())
async def test_open_auto_start(controller):
project = Project(controller=controller, name="Test", auto_start=True)
assert project.status == "opened"
await project.close()
project.start_all = AsyncioMagicMock()
await project.open()
assert project.start_all.called
with patch('gns3server.controller.project.Project.emit_controller_notification'):
project = Project(controller=controller, name="Test", auto_start=True)
assert project.status == "opened"
await project.close()
project.start_all = AsyncioMagicMock()
await project.open()
assert project.start_all.called
def test_is_running(project, node):
+31 -30
View File
@@ -19,7 +19,7 @@ import json
import uuid
import pytest
import aiohttp
from unittest.mock import MagicMock
from unittest.mock import MagicMock, patch
from tests.utils import asyncio_patch
from gns3server.controller.project import Project
@@ -30,35 +30,36 @@ from gns3server.version import __version__
async def test_project_to_topology_empty(tmpdir):
project = Project(name="Test")
topo = project_to_topology(project)
assert topo == {
"project_id": project.id,
"name": "Test",
"auto_start": False,
"auto_close": True,
"auto_open": False,
"scene_width": 2000,
"scene_height": 1000,
"revision": GNS3_FILE_FORMAT_REVISION,
"zoom": 100,
"show_grid": False,
"show_interface_labels": False,
"show_layers": False,
"snap_to_grid": False,
"grid_size": 75,
"drawing_grid_size": 25,
"topology": {
"nodes": [],
"links": [],
"computes": [],
"drawings": []
},
"type": "topology",
"supplier": None,
"variables": None,
"version": __version__
}
with patch('gns3server.controller.project.Project.emit_controller_notification'):
project = Project(name="Test")
topo = project_to_topology(project)
assert topo == {
"project_id": project.id,
"name": "Test",
"auto_start": False,
"auto_close": True,
"auto_open": False,
"scene_width": 2000,
"scene_height": 1000,
"revision": GNS3_FILE_FORMAT_REVISION,
"zoom": 100,
"show_grid": False,
"show_interface_labels": False,
"show_layers": False,
"snap_to_grid": False,
"grid_size": 75,
"drawing_grid_size": 25,
"topology": {
"nodes": [],
"links": [],
"computes": [],
"drawings": []
},
"type": "topology",
"supplier": None,
"variables": None,
"version": __version__
}
async def test_basic_topology(controller):
+2 -2
View File
@@ -255,7 +255,7 @@ async def test_qemu_list_binaries(compute_api, vm):
with asyncio_patch("gns3server.compute.qemu.Qemu.binary_list", return_value=ret) as mock:
response = await compute_api.get("/qemu/binaries".format(project_id=vm["project_id"]))
assert mock.called_with(None)
mock.assert_called_with(None)
assert response.status == 200
assert response.json == ret
@@ -271,7 +271,7 @@ async def test_qemu_list_binaries_filter(compute_api, vm):
with asyncio_patch("gns3server.compute.qemu.Qemu.binary_list", return_value=ret) as mock:
response = await compute_api.get("/qemu/binaries".format(project_id=vm["project_id"]), body={"archs": ["i386"]})
assert response.status == 200
assert mock.called_with(["i386"])
mock.assert_called_with(["i386"])
assert response.json == ret
@@ -186,7 +186,9 @@ async def test_notification(controller_api, http_client, project, controller):
assert b'"cpu_usage_percent"' in response.body
assert b'{"action": "node.created", "event": {"a": "b"}}\n' in response.body
assert project.status == "opened"
controller.notification.project_emit("node.updated", {"a": "b"})
controller.notification.project_emit("node.deleted", {"a": "b"})
controller.notification.project_emit("snapshot.restored", {"a": "b"})
async def test_notification_invalid_id(controller_api):