mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-11 09:25:52 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8a7e80456 | ||
|
|
ab05784c33 | ||
|
|
6983e686ca | ||
|
|
3631202ce5 | ||
|
|
8d8a3247c4 | ||
|
|
d100a132d6 | ||
|
|
52638a9a8d | ||
|
|
9a5af82a28 | ||
|
|
14a618766d | ||
|
|
0137688ba7 | ||
|
|
84db3b9996 | ||
|
|
0a08031d85 | ||
|
|
1a53c9aabf | ||
|
|
1f5085608c | ||
|
|
16f72b4d3d | ||
|
|
3ced41633f | ||
|
|
4fa10be5aa | ||
|
|
f050fc7e00 | ||
|
|
c93aafc9af | ||
|
|
93520b4d6c | ||
|
|
1fb0260ae6 | ||
|
|
763ef24108 | ||
|
|
17aabd6cda | ||
|
|
d94adf4c8f | ||
|
|
4dd9cf2da2 | ||
|
|
e2a3d391d8 | ||
|
|
6c5f54fe57 | ||
|
|
082fbee1bd | ||
|
|
6d97feaced | ||
|
|
8d35089661 | ||
|
|
6455f62447 | ||
|
|
2fb3b1ebab | ||
|
|
58399a9fa8 | ||
|
|
907b305ecf | ||
|
|
57f92db124 | ||
|
|
0f6f943a83 | ||
|
|
2cb76b2274 | ||
|
|
2d2db52a8b | ||
|
|
a8d0818e07 | ||
|
|
f7eb2492d9 | ||
|
|
218522b08c | ||
|
|
470f13f448 | ||
|
|
317aa669ac | ||
|
|
8d160ad5ed | ||
|
|
e3493870b2 | ||
|
|
d466c85385 | ||
|
|
35d4391fc0 | ||
|
|
eea0ab69bd | ||
|
|
22ade94118 | ||
|
|
08ee40548f | ||
|
|
7f05a06766 | ||
|
|
9fd2f58ef7 | ||
|
|
b9b802ebab | ||
|
|
1d86e322e9 | ||
|
|
8eb5f10971 | ||
|
|
cc4783ab98 | ||
|
|
19792f328d | ||
|
|
596d1274a3 | ||
|
|
2f765747b8 | ||
|
|
4fe57b6a15 | ||
|
|
1177626a53 | ||
|
|
c4cc346864 | ||
|
|
8915dfffa5 | ||
|
|
ff027ebd17 | ||
|
|
27d5ac537f | ||
|
|
fe246cd413 | ||
|
|
2bbb560b8e | ||
|
|
1624c7d6ad | ||
|
|
2a3bb81076 | ||
|
|
e0a0dd83d7 | ||
|
|
16ea395618 | ||
|
|
9dd8da4f6e | ||
|
|
54abf85523 | ||
|
|
385fffec56 | ||
|
|
ac86717bc0 | ||
|
|
7b7af33920 | ||
|
|
85fd3ef4a4 | ||
|
|
fbd8f6ce28 | ||
|
|
195da24910 | ||
|
|
b4c7609aeb | ||
|
|
cd9c4c84b6 | ||
|
|
2566de0f5a | ||
|
|
6a069d0af6 | ||
|
|
2789b3802a | ||
|
|
9e1a1337d4 | ||
|
|
466eb8128e | ||
|
|
e41227b5bd | ||
|
|
78a3b8e824 | ||
|
|
4c149e1614 | ||
|
|
473fa98eda | ||
|
|
13d9afd8bc | ||
|
|
b4edbbbaa7 | ||
|
|
02e19800fb | ||
|
|
24bb0ca419 | ||
|
|
6c5f75bf43 | ||
|
|
7afdcbb3d3 | ||
|
|
de27a57a00 | ||
|
|
46d9ada6d8 | ||
|
|
76bd5921c5 | ||
|
|
af3a618306 | ||
|
|
531499bbfb | ||
|
|
7ad3afbdef | ||
|
|
0e18762b36 | ||
|
|
cbc7e59d3f | ||
|
|
5a6e945db2 | ||
|
|
86c0b90951 |
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
|
||||
|
||||
@@ -13,10 +13,10 @@ 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@v3
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# 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
|
||||
|
||||
@@ -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,3 +1,3 @@
|
||||
{
|
||||
"message": "Warning ASA 8 is not officialy supported by GNS3"
|
||||
"message": "Warning ASA 8 is not officially supported by GNS3"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"a": "b"
|
||||
}
|
||||
@@ -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>✔</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>
|
||||
|
||||
@@ -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>✔</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>✔</td> <td>enum</td> <td>Possible values: telnet, vnc, spice, spice+agent, none</td> </tr>
|
||||
<tr><td>cpu_throttling</td> <td>✔</td> <td>integer</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>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>
|
||||
<tr><td>hda_disk_interface</td> <td>✔</td> <td>string</td> <td>QEMU hda interface</td> </tr>
|
||||
@@ -113,8 +118,11 @@ Output
|
||||
<tr><td>project_id</td> <td>✔</td> <td>string</td> <td>Project UUID</td> </tr>
|
||||
<tr><td>qemu_path</td> <td>✔</td> <td>string</td> <td>Path to QEMU</td> </tr>
|
||||
<tr><td>ram</td> <td>✔</td> <td>integer</td> <td>Amount of RAM in MB</td> </tr>
|
||||
<tr><td>replicate_network_connection_state</td> <td>✔</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>✔</td> <td>enum</td> <td>Possible values: started, stopped, suspended</td> </tr>
|
||||
<tr><td>tpm</td> <td>✔</td> <td>boolean</td> <td>Enable the Trusted Platform Module (TPM) in Qemu</td> </tr>
|
||||
<tr><td>uefi</td> <td>✔</td> <td>boolean</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>
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ Output
|
||||
<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</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>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>
|
||||
<tr><td>hda_disk_interface</td> <td>✔</td> <td>string</td> <td>QEMU hda interface</td> </tr>
|
||||
@@ -65,8 +66,11 @@ Output
|
||||
<tr><td>project_id</td> <td>✔</td> <td>string</td> <td>Project UUID</td> </tr>
|
||||
<tr><td>qemu_path</td> <td>✔</td> <td>string</td> <td>Path to QEMU</td> </tr>
|
||||
<tr><td>ram</td> <td>✔</td> <td>integer</td> <td>Amount of RAM in MB</td> </tr>
|
||||
<tr><td>replicate_network_connection_state</td> <td>✔</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>✔</td> <td>enum</td> <td>Possible values: started, stopped, suspended</td> </tr>
|
||||
<tr><td>tpm</td> <td>✔</td> <td>boolean</td> <td>Enable the Trusted Platform Module (TPM) in Qemu</td> </tr>
|
||||
<tr><td>uefi</td> <td>✔</td> <td>boolean</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>
|
||||
|
||||
@@ -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>✔</td> <td>enum</td> <td>Possible values: telnet, vnc, spice, spice+agent, none</td> </tr>
|
||||
<tr><td>cpu_throttling</td> <td>✔</td> <td>integer</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>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>
|
||||
<tr><td>hda_disk_interface</td> <td>✔</td> <td>string</td> <td>QEMU hda interface</td> </tr>
|
||||
@@ -188,8 +197,11 @@ Output
|
||||
<tr><td>project_id</td> <td>✔</td> <td>string</td> <td>Project UUID</td> </tr>
|
||||
<tr><td>qemu_path</td> <td>✔</td> <td>string</td> <td>Path to QEMU</td> </tr>
|
||||
<tr><td>ram</td> <td>✔</td> <td>integer</td> <td>Amount of RAM in MB</td> </tr>
|
||||
<tr><td>replicate_network_connection_state</td> <td>✔</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>✔</td> <td>enum</td> <td>Possible values: started, stopped, suspended</td> </tr>
|
||||
<tr><td>tpm</td> <td>✔</td> <td>boolean</td> <td>Enable the Trusted Platform Module (TPM) in Qemu</td> </tr>
|
||||
<tr><td>uefi</td> <td>✔</td> <td>boolean</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>
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ Output
|
||||
<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</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>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>
|
||||
<tr><td>hda_disk_interface</td> <td>✔</td> <td>string</td> <td>QEMU hda interface</td> </tr>
|
||||
@@ -65,8 +66,11 @@ Output
|
||||
<tr><td>project_id</td> <td>✔</td> <td>string</td> <td>Project UUID</td> </tr>
|
||||
<tr><td>qemu_path</td> <td>✔</td> <td>string</td> <td>Path to QEMU</td> </tr>
|
||||
<tr><td>ram</td> <td>✔</td> <td>integer</td> <td>Amount of RAM in MB</td> </tr>
|
||||
<tr><td>replicate_network_connection_state</td> <td>✔</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>✔</td> <td>enum</td> <td>Possible values: started, stopped, suspended</td> </tr>
|
||||
<tr><td>tpm</td> <td>✔</td> <td>boolean</td> <td>Enable the Trusted Platform Module (TPM) in Qemu</td> </tr>
|
||||
<tr><td>uefi</td> <td>✔</td> <td>boolean</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>
|
||||
|
||||
|
||||
@@ -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>✔</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>✔</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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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",
|
||||
|
||||
@@ -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
|
||||
---------
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -29,6 +29,13 @@
|
||||
"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",
|
||||
@@ -57,6 +64,13 @@
|
||||
"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",
|
||||
@@ -78,6 +92,13 @@
|
||||
"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",
|
||||
@@ -235,6 +256,13 @@
|
||||
}
|
||||
],
|
||||
"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": {
|
||||
@@ -263,6 +291,13 @@
|
||||
"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": {
|
||||
@@ -284,6 +319,13 @@
|
||||
"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": {
|
||||
|
||||
@@ -28,6 +28,13 @@
|
||||
"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",
|
||||
@@ -35,6 +42,13 @@
|
||||
"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",
|
||||
@@ -63,6 +77,13 @@
|
||||
"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",
|
||||
@@ -91,6 +112,13 @@
|
||||
"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",
|
||||
@@ -339,6 +367,13 @@
|
||||
}
|
||||
],
|
||||
"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": {
|
||||
@@ -346,6 +381,13 @@
|
||||
"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": {
|
||||
@@ -374,6 +416,13 @@
|
||||
"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": {
|
||||
@@ -402,6 +451,13 @@
|
||||
"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": {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"status": "stable",
|
||||
"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",
|
||||
"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": {
|
||||
@@ -29,6 +29,13 @@
|
||||
"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",
|
||||
@@ -57,6 +64,13 @@
|
||||
"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",
|
||||
@@ -78,6 +92,13 @@
|
||||
"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",
|
||||
@@ -235,6 +256,13 @@
|
||||
}
|
||||
],
|
||||
"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": {
|
||||
@@ -263,6 +291,13 @@
|
||||
"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": {
|
||||
@@ -284,6 +319,13 @@
|
||||
"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": {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -160,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
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -57,7 +57,7 @@ class CrashReport:
|
||||
Report crash to a third party service
|
||||
"""
|
||||
|
||||
DSN = "https://eb1150edfa1530053154ff1fcb67afd1@o19455.ingest.sentry.io/38482"
|
||||
DSN = "https://535981c5fae1a87b7e8d993590c07c27@o19455.ingest.sentry.io/38482"
|
||||
_instance = None
|
||||
|
||||
def __init__(self):
|
||||
|
||||
+3
-3
@@ -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()))
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.383fdade2fd9dbccffbc.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))}()}();
|
||||
@@ -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"""
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
# or negative for a release candidate or beta (after the base version
|
||||
# number has been incremented)
|
||||
|
||||
__version__ = "2.2.44.1"
|
||||
__version_info__ = (2, 2, 44, -99)
|
||||
__version__ = "2.2.46"
|
||||
__version_info__ = (2, 2, 46, 0)
|
||||
|
||||
if "dev" in __version__:
|
||||
try:
|
||||
|
||||
@@ -311,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,
|
||||
|
||||
+8
-4
@@ -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
-14
@@ -1,19 +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; python_version < '3.12'
|
||||
aiohttp==3.9.0b0; python_version == '3.12'
|
||||
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.34.0,<1.35
|
||||
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
|
||||
@@ -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
@@ -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":
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
@@ -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")
|
||||
]
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
|
||||
Reference in new issue
Block a user