mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-10 09:04:22 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cb8b9a75e | ||
|
|
7009459b0c | ||
|
|
03c94c0bc5 | ||
|
|
568df7e476 | ||
|
|
482b46d343 | ||
|
|
94ee197a6e | ||
|
|
c386b2d046 | ||
|
|
de2d72248e | ||
|
|
5ece48500c | ||
|
|
5eb5658a74 | ||
|
|
3286348a95 | ||
|
|
67661616cf | ||
|
|
6beab9433b | ||
|
|
e59e051961 | ||
|
|
6b3f703f94 | ||
|
|
d44a6756c1 | ||
|
|
6d10d92af2 | ||
|
|
a8aeb63c91 | ||
|
|
6f1feed265 | ||
|
|
e026c1e91f | ||
|
|
40e565d968 | ||
|
|
5162ef2e22 | ||
|
|
1923c37092 | ||
|
|
611570a863 | ||
|
|
99d7d0c769 | ||
|
|
e42b8cb97c | ||
|
|
ed336da304 | ||
|
|
bcf34d0ec8 | ||
|
|
21e9f38437 | ||
|
|
a55c9a5c6a | ||
|
|
041d2bd2d6 | ||
|
|
51c6f3fa31 | ||
|
|
83cbcac01b | ||
|
|
b1224ce9f6 | ||
|
|
a2367d3c04 | ||
|
|
45e0cbeca2 | ||
|
|
1eaabd6b25 | ||
|
|
4eb8491cfa | ||
|
|
b843f94068 | ||
|
|
f71e7aac9f | ||
|
|
945e3e3e8e | ||
|
|
59a89c5f88 | ||
|
|
78c2ded2aa | ||
|
|
6ba40bd5fb | ||
|
|
6005e89181 | ||
|
|
27bcb60580 | ||
|
|
93711fe060 | ||
|
|
363fdb7d10 | ||
|
|
92150fba71 | ||
|
|
c4c71cc838 | ||
|
|
8aada49414 | ||
|
|
496170b4e5 | ||
|
|
731152c75a | ||
|
|
2897325f36 | ||
|
|
8c0899d086 | ||
|
|
d5c73f4ba4 | ||
|
|
77487e4fc3 | ||
|
|
754f55b01b | ||
|
|
b68f7a78a7 | ||
|
|
6c36beb97f | ||
|
|
c231ae77e5 | ||
|
|
e5a76fcf44 | ||
|
|
d926a713b9 | ||
|
|
1a24ebfc19 | ||
|
|
6cf268ca93 | ||
|
|
214bef9d06 | ||
|
|
4646ce684f | ||
|
|
d2534d6fa0 | ||
|
|
3b7dc21ef0 | ||
|
|
0ecea8ffbb | ||
|
|
6741d6d7a9 | ||
|
|
feace0c7dc | ||
|
|
1ee3e14bd3 | ||
|
|
cdedd53339 | ||
|
|
e78b5fa6d6 | ||
|
|
3524e22761 | ||
|
|
10daab21a3 | ||
|
|
22eb6f7d8c | ||
|
|
d556c08def | ||
|
|
8acb2fe37e | ||
|
|
94acf60aef | ||
|
|
c892cf371b | ||
|
|
bfd30f3547 | ||
|
|
095a022033 | ||
|
|
4e34ab8e4f | ||
|
|
8825831106 | ||
|
|
5da5cbd6d8 | ||
|
|
08f540f417 | ||
|
|
1db1a892b4 | ||
|
|
7ff72879dd | ||
|
|
48d0c6b183 | ||
|
|
c051367d4b | ||
|
|
150526b1ff | ||
|
|
971e86d254 | ||
|
|
6847e19847 | ||
|
|
3a479d7ea6 | ||
|
|
9a6978902d | ||
|
|
6294ad9e76 | ||
|
|
2c938b2c19 | ||
|
|
03b7d9191b | ||
|
|
87c87ca3cb | ||
|
|
dfba40fee2 | ||
|
|
f576bedfaf | ||
|
|
4e61cc811e | ||
|
|
c9c6a5a762 | ||
|
|
e797ad1b9f | ||
|
|
a50141fcbf | ||
|
|
852151f836 | ||
|
|
e5807e5a8c | ||
|
|
87a26d5da0 | ||
|
|
30cbfe2154 | ||
|
|
4bbf7c2ed2 | ||
|
|
7a8c1e8f5d | ||
|
|
7bb5202bdb | ||
|
|
082206a7db | ||
|
|
360a819e91 | ||
|
|
adbef787c3 | ||
|
|
685963b85d | ||
|
|
e614ed79f4 | ||
|
|
bb47cc87e7 | ||
|
|
6120736c91 | ||
|
|
7542b28793 | ||
|
|
4d0cb32bd0 | ||
|
|
055a78bade | ||
|
|
fad52ea2fc | ||
|
|
d8054c7cb4 | ||
|
|
91570f475f | ||
|
|
42cda3af2b | ||
|
|
e6be6bc958 | ||
|
|
b7f8fb283b | ||
|
|
72d5b5e7cc | ||
|
|
8cce0eedee | ||
|
|
11c53c128e | ||
|
|
17b56ac7cb | ||
|
|
aca7344212 | ||
|
|
3c5bbe04dc | ||
|
|
c213cae500 | ||
|
|
1043be02a6 | ||
|
|
56c25727b6 | ||
|
|
0b854ffceb | ||
|
|
366e904698 | ||
|
|
16c84e23a9 | ||
|
|
64f172fe20 | ||
|
|
bb0206d7d2 | ||
|
|
9de61cd671 | ||
|
|
9e6ccc3f61 | ||
|
|
4c339eade1 | ||
|
|
128e494134 | ||
|
|
0e6b97b27b | ||
|
|
235a127111 | ||
|
|
bb51146e80 | ||
|
|
e6944276a6 | ||
|
|
704858fd8d | ||
|
|
87ede50827 | ||
|
|
24fe67f82b | ||
|
|
18c878429f | ||
|
|
6c3a070733 | ||
|
|
a157ef5a8a | ||
|
|
5244ae6d4c | ||
|
|
db47615d43 | ||
|
|
603683e2c5 | ||
|
|
e45bc5aec1 | ||
|
|
a3ee1d9ee6 | ||
|
|
0e95e7e023 | ||
|
|
1748250179 | ||
|
|
c8ea22c651 | ||
|
|
d16cb5ef89 | ||
|
|
004acdc271 | ||
|
|
e182f53d69 | ||
|
|
aef8f0dff3 | ||
|
|
b6a021dabd | ||
|
|
5dab0c2587 | ||
|
|
5d1fdceb98 | ||
|
|
5743d47327 | ||
|
|
ca69b01d11 | ||
|
|
dd785b61cf | ||
|
|
0f154e5f29 | ||
|
|
f9c4c82da6 | ||
|
|
3a136a46a1 | ||
|
|
a6a35e7c43 | ||
|
|
163a867f00 | ||
|
|
d2b7c9bcbf | ||
|
|
fb8df1cc6b | ||
|
|
d063b3e39d | ||
|
|
83fbd1f627 | ||
|
|
1aa6fe8535 | ||
|
|
de2b9caeeb | ||
|
|
362701f5aa | ||
|
|
91244456f5 | ||
|
|
88ab528977 | ||
|
|
4843084158 | ||
|
|
01db2d2a86 | ||
|
|
f2ddef855f | ||
|
|
ec02150fd2 | ||
|
|
a56b816c1a | ||
|
|
9d3f7c79a2 | ||
|
|
c684c554bf | ||
|
|
9acb2ceda1 | ||
|
|
053828f3e8 | ||
|
|
f747b3a880 | ||
|
|
750590d0db | ||
|
|
347035a99b | ||
|
|
0db0f6256b | ||
|
|
99d9728360 | ||
|
|
6a1eef0627 |
No files matched your search
@@ -0,0 +1,43 @@
|
||||
name: publish-api-documentation
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- v3.*
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: "gh-pages"
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.6
|
||||
- name: Merge changes from 3.0 branch
|
||||
run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
git merge origin/3.0 -X theirs
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
||||
- name: Install GNS3 server
|
||||
run: |
|
||||
python setup.py install
|
||||
- name: Generate the API documentation
|
||||
run: |
|
||||
cd scripts
|
||||
python3 publish_api_documentation.py
|
||||
- name: Publish the API documentation
|
||||
run: |
|
||||
git add docs
|
||||
git status
|
||||
git commit -m "Publish API documentation"
|
||||
git push
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.6, 3.7, 3.8]
|
||||
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -1,5 +1,114 @@
|
||||
# Change Log
|
||||
|
||||
## 2.2.26 08/10/2021
|
||||
|
||||
* Release web UI 2.2.26
|
||||
* Sort symbols by theme. Fixes https://github.com/GNS3/gns3-gui/issues/3230
|
||||
* Fix memory percentage left warning. Fixes #1966
|
||||
* Update affinity symbols. Fixes https://github.com/GNS3/gns3-gui/issues/3232
|
||||
|
||||
## 2.2.25 14/09/2021
|
||||
|
||||
* Release web UI 2.2.25
|
||||
* Fix issue preventing to use custom nested symbols. Fixes #1969
|
||||
* Updated affinity symbols
|
||||
* Fix qemu-img rebase code to support Qemu 6.1. Ref https://github.com/GNS3/gns3-server/pull/1962
|
||||
* Reinstate qemu-img rebase
|
||||
* Return disk usage for partition that contains the default project directory. Fixes #1947
|
||||
* Explicitly require setuptools, utils/get_resource.py imports pkg_resources
|
||||
|
||||
## 2.2.24 25/08/2021
|
||||
|
||||
* Release web UI 2.2.24
|
||||
* Fix issue when searching for image with relative path. Fixes #1925
|
||||
* Fix wrong error when NAT interface is not allowed. Fixes #1943
|
||||
* Fix incorrect Qemu binary selected when importing template. Fixes https://github.com/GNS3/gns3-gui/issues/3216
|
||||
* Fix error when updating a link style. Fixes https://github.com/GNS3/gns3-gui/issues/2461
|
||||
* Some fixes for early support for Python3.10 The loop parameter has been removed from most of asyncio‘s high-level API following deprecation in Python 3.8.
|
||||
* Early support for Python3.10 Fixes #1940
|
||||
* Bump pywin32 from 300 to 301
|
||||
|
||||
## 2.2.23 05/08/2021
|
||||
|
||||
* Release web UI 2.2.23
|
||||
* Fix hostname inconsistencies during script execution
|
||||
* Add option `--without-kvm`
|
||||
* Add a `reload` server endpoint. Fixes #1926
|
||||
* Handle -no-kvm param deprecated in Qemu >= v5.2
|
||||
* Fix binary websocket access to the console
|
||||
* Change how to generate random MAC addresses
|
||||
* setup.py: prevent installing tests directory
|
||||
* Support cloning of encrypted qcow2 base image files
|
||||
* Fix VMware VM support on Linux and Windows. Fixes #1919
|
||||
|
||||
## 2.2.22 10/06/2021
|
||||
|
||||
* Fix VMware support on macOS BigSur
|
||||
* Link style support. Fixes https://github.com/GNS3/gns3-gui/issues/2461
|
||||
* Release web UI version 2.2.22
|
||||
* Preserve auto_start/auto_open/auto_close when restoring snapshot
|
||||
* Fix uBridge errors for cloud nodes not visible in logs. Fixes #1895
|
||||
* Prevent directory traversal. Fixes #1894
|
||||
|
||||
## 2.2.21 10/05/2021
|
||||
|
||||
* Release Web-Ui v2.2.21
|
||||
* Improvements for get symbol dimensions endpoint. Ref #1885
|
||||
|
||||
## 2.2.20 09/04/2021
|
||||
|
||||
* Release Web UI version 2.2.20
|
||||
* Fix packet capture with HTTPS remote server. Fixes #1882
|
||||
* Sync appliance files and remove old ones after sync with online repo. Fixes #1876
|
||||
* Upgrade dependencies
|
||||
* Fix export for missing files
|
||||
* Fix issue when trying to export temporary Dynamips files.
|
||||
|
||||
## 2.2.19 05/03/2021
|
||||
|
||||
* Launch projects marked for auto open after SIGHUP is received
|
||||
* Release Web UI 2.2.19
|
||||
* Fix console type error when creating Ethernet switch node. Fixes #1873
|
||||
* Upgrade Jinja to version 2.11.3. Fixes #1865
|
||||
|
||||
## 2.2.18 16/02/2021
|
||||
|
||||
* SIGHUP: remove projects with an empty project directory.
|
||||
* Release Web UI 2.2.18
|
||||
* Catch OSError exception in psutil. Fixes https://github.com/GNS3/gns3-gui/issues/3127
|
||||
* Expose 'auto_open' and 'auto_start' properties in API when creating project. Fixes https://github.com/GNS3/gns3-gui/issues/3119
|
||||
* Add mtools package information. Ref https://github.com/GNS3/gns3-gui/issues/3076
|
||||
* Fix warning: 'ide-drive' is deprecated when using recent version of Qemu. Fixes https://github.com/GNS3/gns3-gui/issues/3101
|
||||
* Fix bug when starting of vpcs stopped with "quit". Fixes https://github.com/GNS3/gns3-gui/issues/3110
|
||||
* Fix WinError 0 handling
|
||||
* Stop uBridge if VPCS node has been terminated. Ref https://github.com/GNS3/gns3-gui/issues/3110
|
||||
* Allow cloned QEMU disk images to be resized before the node starts, by cloning the disk image in response to a resize request instead of waiting until the node starts.
|
||||
* Fix(readme): update python version from 3.5.3 to 3.6
|
||||
* Use HDD disk image as startup QEMU config disk
|
||||
* Create config disk property false by default for Qemu templates
|
||||
* Set default disk interface type to "none".
|
||||
* Add explicit option to automatically create or not the config disk. Off by default.
|
||||
* QEMU config disk support
|
||||
|
||||
|
||||
## 2.2.17 04/12/2020
|
||||
|
||||
* Close and remove projects deleted from disks after SIGHUP signal is received.
|
||||
* Release Web Ui 2.2.17
|
||||
* New config file options to configure the VNC console port range.
|
||||
* Use asyncio.all_tasks instead of deprecated method for Python 3.9 compatibility.
|
||||
|
||||
## 2.2.16 05/11/2020
|
||||
|
||||
* Option to allocate or not the vCPUs and RAM settings for the GNS3 VM. Fixes https://github.com/GNS3/gns3-gui/issues/3069
|
||||
* Release Web UI version 2.2.16
|
||||
* Fix wrong defaults for images_path, configs_path, appliances_path. Fixes #1829
|
||||
* Use EnvironmentFile for Systemd service. Ref https://github.com/GNS3/gns3-gui/issues/3048
|
||||
* Fix SSL support for controller and local compute. Fixes #1826
|
||||
* Prevent WIC to be added/removed while Dynamips router is running. Fixes https://github.com/GNS3/gns3-gui/issues/3082
|
||||
* Fix bug with application id allocation for IOU nodes. Fixes #3079
|
||||
* Allow commas in image paths and VM name for Qemu VMs. Fixes https://github.com/GNS3/gns3-gui/issues/3065
|
||||
|
||||
## 2.2.15 07/10/2020
|
||||
|
||||
* Fix symbol retrieval issue. Ref #1824
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ RUN apt-get install -y vpcs ubridge
|
||||
ADD . /server
|
||||
WORKDIR /server
|
||||
|
||||
RUN pip3 install -r /server/requirements.txt
|
||||
RUN pip3 install --no-cache-dir -r /server/requirements.txt
|
||||
|
||||
EXPOSE 3080
|
||||
|
||||
|
||||
+3
-2
@@ -24,8 +24,9 @@ In addition of Python dependencies listed in a section below, other software may
|
||||
* `Dynamips <https://github.com/GNS3/dynamips/>`_ is required for running IOS routers (using real IOS images) as well as the internal switches and hubs.
|
||||
* `VPCS <https://github.com/GNS3/vpcs/>`_ is recommended, it is a builtin node simulating a very simple computer to perform connectitivy tests using ping, traceroute etc.
|
||||
* Qemu is strongly recommended on Linux, as most node types are based on Qemu, for example Cisco IOSv and Arista vEOS.
|
||||
* libvirt is recommended (Linux only), as it's needed for the NAT cloud
|
||||
* libvirt is recommended (Linux only), as it's needed for the NAT cloud.
|
||||
* Docker is optional (Linux only), some nodes are based on Docker.
|
||||
* mtools is recommended to support data transfer to/from QEMU VMs using virtual disks.
|
||||
* i386-libraries of libc and libcrypto are optional (Linux only), they are only needed to run IOU based nodes.
|
||||
|
||||
Branches
|
||||
@@ -59,7 +60,7 @@ You must be connected to the Internet in order to install the dependencies.
|
||||
|
||||
Dependencies:
|
||||
|
||||
- Python 3.5.3, setuptools and the ones listed `here <https://github.com/GNS3/gns3-server/blob/master/requirements.txt>`_
|
||||
- Python 3.6, setuptools and the ones listed `here <https://github.com/GNS3/gns3-server/blob/master/requirements.txt>`_
|
||||
|
||||
The following commands will install some of these dependencies:
|
||||
|
||||
|
||||
@@ -28,10 +28,19 @@ report_errors = True
|
||||
console_start_port_range = 5000
|
||||
; Last console port of the range allocated to devices
|
||||
console_end_port_range = 10000
|
||||
|
||||
; First VNC console port of the range allocated to devices.
|
||||
; The value MUST BE >= 5900 and <= 65535
|
||||
vnc_console_start_port_range = 5900
|
||||
; Last VNC console port of the range allocated to devices
|
||||
; The value MUST BE >= 5900 and <= 65535
|
||||
vnc_console_end_port_range = 10000
|
||||
|
||||
; First port of the range allocated for inter-device communication. Two ports are allocated per link.
|
||||
udp_start_port_range = 20000
|
||||
; Last port of the range allocated for inter-device communication. Two ports are allocated per link
|
||||
udp_end_port_range = 30000
|
||||
|
||||
; uBridge executable location, default: search in PATH
|
||||
;ubridge_path = ubridge
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-rrequirements.txt
|
||||
|
||||
pytest==5.4.3
|
||||
flake8==3.8.3
|
||||
pytest-timeout==1.4.1
|
||||
pytest==6.2.4
|
||||
flake8==3.9.2
|
||||
pytest-timeout==1.4.2
|
||||
pytest-aiohttp==0.3.0
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "6WIND Turbo Router",
|
||||
"category": "router",
|
||||
"description": "6WIND Turbo Router is a high performance, ready-to-use software virtual router. It can be deployed bare metal or in virtual machines on commercial-off-the-shelf (COTS) servers. It is a carrier-grade solution for Service Prodivers aiming at using white boxes to deploy network functions. Typical use-cases are transit/peering router, IPsec VPN gateway and CGNAT.",
|
||||
"vendor_name": "6WIND",
|
||||
"vendor_url": "https://www.6wind.com/",
|
||||
"documentation_url": "https://doc.6wind.com/turbo-router-3/latest/turbo-router/",
|
||||
"product_name": "6WIND Turbo Router",
|
||||
"product_url": "https://www.6wind.com/vrouter-solutions/turbo-router/",
|
||||
"registry_version": 4,
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Default username / password is admin / admin.",
|
||||
"symbol": "6wind.svg",
|
||||
"port_name_format": "eth{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 8,
|
||||
"ram": 4096,
|
||||
"cpus": 4,
|
||||
"hda_disk_interface": "virtio",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "c",
|
||||
"kvm": "require",
|
||||
"options": "-cpu host"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "6wind-vrouter-tr-ae-x86_64-v3.1.4.m1.qcow2",
|
||||
"version": "3.1.4.m1",
|
||||
"md5sum": "bc84b81fba4f2f01eda6a338469e37a5",
|
||||
"filesize": 693829632,
|
||||
"download_url": "https://portal.6wind.com/register.php?utm_campaign=GNS3-2021-EVAL"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "3.1.4.m1",
|
||||
"images": {
|
||||
"hda_disk_image": "6wind-vrouter-tr-ae-x86_64-v3.1.4.m1.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -27,10 +27,24 @@
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "vEOS-lab-4.25.0FX-LDP-RSVP.vmdk",
|
||||
"version": "4.25.0FX",
|
||||
"md5sum": "b7c2efdbe48301a78f124db989710346",
|
||||
"filesize": 468647936,
|
||||
"filename": "vEOS-lab-4.26.2F.vmdk",
|
||||
"version": "4.26.2F",
|
||||
"md5sum": "de8ce9750fddb63bd3f71bccfcd7651e",
|
||||
"filesize": 475332608,
|
||||
"download_url": "https://www.arista.com/en/support/software-download"
|
||||
},
|
||||
{
|
||||
"filename": "vEOS-lab-4.25.3M.vmdk",
|
||||
"version": "4.25.3M",
|
||||
"md5sum": "2f196969036b4d283e86f15118d59c26",
|
||||
"filesize": 451543040,
|
||||
"download_url": "https://www.arista.com/en/support/software-download"
|
||||
},
|
||||
{
|
||||
"filename": "vEOS-lab-4.24.3M.vmdk",
|
||||
"version": "4.24.3M",
|
||||
"md5sum": "0a28e44c7ce4a8965f24a4a463a89b7d",
|
||||
"filesize": 455213056,
|
||||
"download_url": "https://www.arista.com/en/support/software-download"
|
||||
},
|
||||
{
|
||||
@@ -204,10 +218,24 @@
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "4.25.0FX",
|
||||
"name": "4.26.2F",
|
||||
"images": {
|
||||
"hda_disk_image": "Aboot-veos-serial-8.0.0.iso",
|
||||
"hdb_disk_image": "vEOS-lab-4.25.0FX-LDP-RSVP.vmdk"
|
||||
"hdb_disk_image": "vEOS-lab-4.26.2F.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "4.25.3M",
|
||||
"images": {
|
||||
"hda_disk_image": "Aboot-veos-serial-8.0.0.iso",
|
||||
"hdb_disk_image": "vEOS-lab-4.25.3M.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "4.24.3M",
|
||||
"images": {
|
||||
"hda_disk_image": "Aboot-veos-serial-8.0.0.iso",
|
||||
"hdb_disk_image": "vEOS-lab-4.24.3M.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -23,12 +23,19 @@
|
||||
"hdb_disk_interface": "ide",
|
||||
"hdc_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "vnc",
|
||||
"console_type": "telnet",
|
||||
"kvm": "require",
|
||||
"options": "-nographic",
|
||||
"process_priority": "normal"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "arubaoscx-disk-image-genericx86-p4-20201110192651.vmdk",
|
||||
"version": "10.06.0001",
|
||||
"md5sum": "f8b45bc52f6bad79b5ff563e0c1ea73b",
|
||||
"filesize": 380304896,
|
||||
"download_url": "https://asp.arubanetworks.com/"
|
||||
},
|
||||
{
|
||||
"filename": "arubaoscx-disk-image-genericx86-p4-20200311173823.vmdk",
|
||||
"version": "10.04.1000",
|
||||
@@ -45,6 +52,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "10.06.0001",
|
||||
"images": {
|
||||
"hda_disk_image": "arubaoscx-disk-image-genericx86-p4-20201110192651.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "10.04.1000",
|
||||
"images": {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "Aruba VGW",
|
||||
"category": "firewall",
|
||||
"description": "Aruba Virtual Gateways allow customers to bring their public cloud infrastructure to the SD-WAN fabric and facilitate connectivity between branches and the public cloud.",
|
||||
"vendor_name": "HPE Aruba",
|
||||
"vendor_url": "arubanetworks.com",
|
||||
"documentation_url": "https://asp.arubanetworks.com/downloads;products=Aruba%20SD-WAN",
|
||||
"product_name": "Aruba SD-WAN Virtual Gateway",
|
||||
"product_url": "https://www.arubanetworks.com/products/networking/gateways-and-controllers/",
|
||||
"registry_version": 4,
|
||||
"status": "stable",
|
||||
"availability": "service-contract",
|
||||
"maintainer": "Aruba",
|
||||
"maintainer_email": "mitchell.pompe@hpe.com",
|
||||
"usage": "The device must receive an user-data.iso image, which can be mounted to the CD/DVD-ROM and retrieved from Aruba Central. https://help.central.arubanetworks.com/latest/documentation/online_help/content/gateways/vgw/vgw_man-esxi-gen-ud.htm . By default the VGW can be used with VNC, but once provisioned the command '#serial console redirect enable' will enable telnet usage for GNS3.",
|
||||
"symbol": ":/symbols/classic/gateway.svg",
|
||||
"first_port_name": "mgmt",
|
||||
"port_name_format": "GE0/0/{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 4,
|
||||
"ram": 4096,
|
||||
"cpus": 3,
|
||||
"hda_disk_interface": "ide",
|
||||
"hdb_disk_interface": "ide",
|
||||
"hdc_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "vnc",
|
||||
"kernel_command_line": "",
|
||||
"kvm": "require",
|
||||
"options": "-smp cores=3,threads=1,sockets=1 -cpu host",
|
||||
"process_priority": "normal"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ArubaOS_VGW_8.6.0.4-2.2.0.0_76905-disk1.vmdk",
|
||||
"version": "8.6.0.4-2.2.0.0",
|
||||
"md5sum": "24d3fdcbec01c1faa2d4e68659024b40",
|
||||
"filesize": 226974208,
|
||||
"download_url": "https://asp.arubanetworks.com/downloads"
|
||||
},
|
||||
{
|
||||
"filename": "ArubaOS_VGW_8.6.0.4-2.2.0.0_76905-disk2.vmdk",
|
||||
"version": "8.6.0.4-2.2.0.0",
|
||||
"md5sum": "354edd27dc320c739919f55766737d06",
|
||||
"filesize": 4203008,
|
||||
"download_url": "https://asp.arubanetworks.com/downloads"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "8.6.0.4-2.2.0.0",
|
||||
"images": {
|
||||
"hda_disk_image": "ArubaOS_VGW_8.6.0.4-2.2.0.0_76905-disk1.vmdk",
|
||||
"hdb_disk_image": "ArubaOS_VGW_8.6.0.4-2.2.0.0_76905-disk2.vmdk"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
"console_type": "telnet",
|
||||
"kernel_command_line": "ide_generic.probe_mask=0x01 ide_core.chs=0.0:980,16,32 auto nousb console=ttyS0,9600 bigphysarea=65536 ide1=noprobe no-hlt",
|
||||
"kvm": "disable",
|
||||
"options": "-no-kvm -icount auto -hdachs 980,16,32",
|
||||
"options": "-machine accel=tcg -icount auto -hdachs 980,16,32",
|
||||
"cpu_throttling": 80,
|
||||
"process_priority": "low"
|
||||
},
|
||||
|
||||
@@ -25,6 +25,20 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "asav9-15-1.qcow2",
|
||||
"version": "9.15.1",
|
||||
"md5sum": "4e8747667f52e9046979f126128a61d1",
|
||||
"filesize": 252444672,
|
||||
"download_url": "https://software.cisco.com/download/home/286119613/type/280775065/release/9.15.1"
|
||||
},
|
||||
{
|
||||
"filename": "asav9-14-1.qcow2",
|
||||
"version": "9.14.1",
|
||||
"md5sum": "03d89e18e7f8ad00fe8e979c4790587d",
|
||||
"filesize": 211877888,
|
||||
"download_url": "https://software.cisco.com/download/home/286119613/type/280775065/release/9.14.1"
|
||||
},
|
||||
{
|
||||
"filename": "asav9-12-2-9.qcow2",
|
||||
"version": "9.12.2-9",
|
||||
@@ -90,6 +104,18 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "9.15.1",
|
||||
"images": {
|
||||
"hda_disk_image": "asav9-15-1.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "9.14.1",
|
||||
"images": {
|
||||
"hda_disk_image": "asav9-14-1.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "9.12.2-9",
|
||||
"images": {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "Cisco Catalyst 8000V",
|
||||
"category": "router",
|
||||
"description": "The Cisco Catalyst 8000V Edge Software is a virtual, form-factor router deployed on a virtual machine (VM) running on an x86 server hardware.",
|
||||
"vendor_name": "Cisco",
|
||||
"vendor_url": "http://www.cisco.com/",
|
||||
"documentation_url": "https://www.cisco.com/c/en/us/td/docs/routers/C8000V/Configuration/c8000v-installation-configuration-guide.html",
|
||||
"product_name": "c8000v",
|
||||
"product_url": "https://www.cisco.com/c/en/us/support/routers/catalyst-8000v-edge-software/series.html",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "There is no default password and enable password. A default configuration is present.",
|
||||
"port_name_format": "Gi{port1}",
|
||||
"qemu": {
|
||||
"adapter_type": "vmxnet3",
|
||||
"adapters": 4,
|
||||
"ram": 4096,
|
||||
"hda_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "c8000v-universalk9_8G_serial.17.04.01a.qcow2",
|
||||
"version": "17.04.01a 8G",
|
||||
"md5sum": "5c1dd1d3757ea43b5b02e0af7a010525",
|
||||
"filesize": 1623130112,
|
||||
"download_url": "https://software.cisco.com/download/home/286327102/type/282046477/release/Bengaluru-17.4.1a"
|
||||
},
|
||||
{
|
||||
"filename": "c8000v-universalk9_8G_serial.17.04.01b.qcow2",
|
||||
"version": "17.04.01b 8G",
|
||||
"md5sum": "84aebb7f5f38bdd4df8e7607643027be",
|
||||
"filesize": 1623130112,
|
||||
"download_url": "https://software.cisco.com/download/home/286327102/type/282046477/release/Bengaluru-17.4.1b"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "17.04.01a 8G",
|
||||
"images": {
|
||||
"hda_disk_image": "c8000v-universalk9_8G_serial.17.04.01a.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "17.04.01b 8G",
|
||||
"images": {
|
||||
"hda_disk_image": "c8000v-universalk9_8G_serial.17.04.01b.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -31,6 +31,27 @@
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files",
|
||||
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/IOSv_startup_config.img/download"
|
||||
},
|
||||
{
|
||||
"filename": "vios-adventerprisek9-m.spa.159-3.m3.qcow2",
|
||||
"version": "15.9(3)M3",
|
||||
"md5sum": "12893843af18e4c62f13d07266755653",
|
||||
"filesize": 57296384,
|
||||
"download_url": "https://learningnetworkstore.cisco.com/myaccount"
|
||||
},
|
||||
{
|
||||
"filename": "vios-adventerprisek9-m.spa.159-3.m2.qcow2",
|
||||
"version": "15.9(3)M2",
|
||||
"md5sum": "a19e998bc3086825c751d125af722329",
|
||||
"filesize": 57308672,
|
||||
"download_url": "https://learningnetworkstore.cisco.com/myaccount"
|
||||
},
|
||||
{
|
||||
"filename": "vios-adventerprisek9-m.spa.158-3.m2.qcow2",
|
||||
"version": "15.8(3)M2",
|
||||
"md5sum": "40e3d25b5b0cb13d639fcd2cf18e9965",
|
||||
"filesize": 57129984,
|
||||
"download_url": "https://learningnetworkstore.cisco.com/myaccount"
|
||||
},
|
||||
{
|
||||
"filename": "vios-adventerprisek9-m.vmdk.SPA.157-3.M3",
|
||||
"version": "15.7(3)M3",
|
||||
@@ -61,6 +82,27 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "15.9(3)M3",
|
||||
"images": {
|
||||
"hda_disk_image": "vios-adventerprisek9-m.spa.159-3.m3.qcow2",
|
||||
"hdb_disk_image": "IOSv_startup_config.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "15.9(3)M2",
|
||||
"images": {
|
||||
"hda_disk_image": "vios-adventerprisek9-m.spa.159-3.m2.qcow2",
|
||||
"hdb_disk_image": "IOSv_startup_config.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "15.8(3)M2",
|
||||
"images": {
|
||||
"hda_disk_image": "vios-adventerprisek9-m.spa.158-3.m2.qcow2",
|
||||
"hdb_disk_image": "IOSv_startup_config.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "15.7(3)M3",
|
||||
"images": {
|
||||
|
||||
@@ -23,6 +23,20 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "vios_l2-adventerprisek9-m.ssa.high_iron_20200929.qcow2",
|
||||
"version": "15.2(20200924:215240)",
|
||||
"md5sum": "99ecab32de12410c533e6abd4e9710aa",
|
||||
"filesize": 90409984,
|
||||
"download_url": "https://learningnetworkstore.cisco.com/myaccount"
|
||||
},
|
||||
{
|
||||
"filename": "vios_l2-adventerprisek9-m.ssa.high_iron_20190423.qcow2",
|
||||
"version": "15.2(6.0.81)E",
|
||||
"md5sum": "71cacb678f98a106f99e889b97b34686",
|
||||
"filesize": 44950016,
|
||||
"download_url": "https://learningnetworkstore.cisco.com/myaccount"
|
||||
},
|
||||
{
|
||||
"filename": "vios_l2-adventerprisek9-m.SSA.high_iron_20180619.qcow2",
|
||||
"version": "15.2.1",
|
||||
@@ -46,6 +60,18 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "15.2(20200924:215240)",
|
||||
"images": {
|
||||
"hda_disk_image": "vios_l2-adventerprisek9-m.ssa.high_iron_20200929.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "15.2(6.0.81)E",
|
||||
"images": {
|
||||
"hda_disk_image": "vios_l2-adventerprisek9-m.ssa.high_iron_20190423.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "15.2.1",
|
||||
"images": {
|
||||
|
||||
@@ -25,6 +25,20 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "nexus9500v64.10.1.1.qcow2",
|
||||
"version": "9500v 10.1.1",
|
||||
"md5sum": "35672370b0f43e725d5b2d92488524f0",
|
||||
"filesize": 1592000512,
|
||||
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/10.1(1)"
|
||||
},
|
||||
{
|
||||
"filename": "nexus9500v.9.3.7.qcow2",
|
||||
"version": "9500v 9.3.7",
|
||||
"md5sum": "65f669e0dd379a05a8cdbb9d7592a064",
|
||||
"filesize": 1986068480,
|
||||
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/9.3(7)"
|
||||
},
|
||||
{
|
||||
"filename": "nexus9500v.9.3.3.qcow2",
|
||||
"version": "9500v 9.3.3",
|
||||
@@ -148,6 +162,20 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "9500v 10.1.1",
|
||||
"images": {
|
||||
"bios_image": "OVMF-20160813.fd",
|
||||
"hda_disk_image": "nexus9500v64.10.1.1.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "9500v 9.3.7",
|
||||
"images": {
|
||||
"bios_image": "OVMF-20160813.fd",
|
||||
"hda_disk_image": "nexus9500v.9.3.7.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "9500v 9.3.3",
|
||||
"images": {
|
||||
|
||||
@@ -11,19 +11,27 @@
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Default username is cumulus and password is CumulusLinux!",
|
||||
"usage": "Default username is cumulus and password is CumulusLinux! in version 4.1 and earlier, and cumulus in version 4.2 and later.",
|
||||
"first_port_name": "eth0",
|
||||
"port_name_format": "swp{port1}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 7,
|
||||
"ram": 512,
|
||||
"ram": 768,
|
||||
"hda_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "cumulus-linux-4.3.0-vx-amd64-qemu.qcow2",
|
||||
"version": "4.3.0",
|
||||
"md5sum": "aba2f0bb462b26a208afb6202bc97d51",
|
||||
"filesize": 2819325952,
|
||||
"download_url": "https://cumulusnetworks.com/cumulus-vx/download/",
|
||||
"direct_download_url": "https://d2cd9e7ca6hntp.cloudfront.net/public/CumulusLinux-4.3.0/cumulus-linux-4.3.0-vx-amd64-qemu.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "cumulus-linux-4.2.0-vx-amd64-qemu.qcow2",
|
||||
"version": "4.2.0",
|
||||
@@ -222,6 +230,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "4.3.0",
|
||||
"images": {
|
||||
"hda_disk_image": "cumulus-linux-4.3.0-vx-amd64-qemu.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "4.2.0",
|
||||
"images": {
|
||||
|
||||
@@ -11,29 +11,29 @@
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Default username/password is vyatta/vyatta. DANOS will live boot and drop into a shell. DANOS can then be installed inside the VM by typing install image. Defaults to using a telnet console, but the vnc console can provide additional help if it's not booting.",
|
||||
"usage": "Default username / password is tmpuser / tmppwd. DANOS will live boot and drop into a shell. DANOS can then be installed inside the VM by typing install image. Defaults to using a telnet console, but the vnc console can provide additional help if it's not booting.",
|
||||
"symbol": ":/symbols/affinity/circle/gray/router_cloud.svg",
|
||||
"port_name_format": "dp0p{1}s{0}",
|
||||
"port_name_format": "dp0s{3}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 3,
|
||||
"adapters": 8,
|
||||
"ram": 4096,
|
||||
"cpus": 2,
|
||||
"cpus": 4,
|
||||
"hda_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "dc",
|
||||
"kvm": "allow",
|
||||
"boot_priority": "cd",
|
||||
"kvm": "require",
|
||||
"options": "-cpu host"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "danos-1908-amd64-vrouter.iso",
|
||||
"version": "1908",
|
||||
"md5sum": "e850b6aa2859de1075c11b9149fa50f4",
|
||||
"filesize": 409993216,
|
||||
"download_url": "https://danosproject.atlassian.net/wiki/spaces/DAN/pages/753667/DANOS+1908",
|
||||
"direct_download_url": "http://repos.danosproject.org.s3-website-us-west-1.amazonaws.com/images/danos-1908-amd64-vrouter.iso"
|
||||
"filename": "danos-2012-base-amd64.iso",
|
||||
"version": "2012",
|
||||
"md5sum": "fb7a60dc9afecdb274464832b3ab1ccb",
|
||||
"filesize": 441450496,
|
||||
"download_url": "https://danosproject.atlassian.net/wiki/spaces/DAN/pages/892141595/DANOS+2012",
|
||||
"direct_download_url": "https://s3-us-west-1.amazonaws.com/2012.repos.danosproject.org/2012/iso/danos-2012-base-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "empty8G.qcow2",
|
||||
@@ -46,10 +46,10 @@
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "1908",
|
||||
"name": "2012",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "danos-1908-amd64-vrouter.iso"
|
||||
"cdrom_image": "danos-2012-base-amd64.iso"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
"options": "-cpu core2duo"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "EXOS-VM_v31.1.1.3.qcow2",
|
||||
"version": "31.1.1.3",
|
||||
"md5sum": "e4936ad94a5304bfeeca8dfc6f285cc0",
|
||||
"filesize": 561512448,
|
||||
"direct_download_url": "https://akamai-ep.extremenetworks.com/Extreme_P/github-en/Virtual_EXOS/EXOS-VM_v31.1.1.3.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "EXOS-VM_v30.7.1.1.qcow2",
|
||||
"version": "30.7.1.1",
|
||||
@@ -91,6 +98,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "31.1.1.3",
|
||||
"images": {
|
||||
"hda_disk_image": "EXOS-VM_v31.1.1.3.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "30.7.1.1",
|
||||
"images": {
|
||||
|
||||
@@ -26,6 +26,27 @@
|
||||
"options": "-nographic"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "VOSSGNS3.8.4.0.0.qcow2",
|
||||
"version": "v8.4.0.0",
|
||||
"md5sum": "f457e7da3c1dec50670624c421333ef3",
|
||||
"filesize": 386203648,
|
||||
"direct_download_url": "https://akamai-ep.extremenetworks.com/Extreme_P/github-en/Virtual_VOSS/VOSSGNS3.8.4.0.0.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "VOSSGNS3.8.3.0.0.qcow2",
|
||||
"version": "v8.3.0.0",
|
||||
"md5sum": "e1c789e439c5951728e349cf44690230",
|
||||
"filesize": 384696320,
|
||||
"direct_download_url": "https://akamai-ep.extremenetworks.com/Extreme_P/github-en/Virtual_VOSS/VOSSGNS3.8.3.0.0.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "VOSSGNS3.8.2.0.0.qcow2",
|
||||
"version": "v8.2.0.0",
|
||||
"md5sum": "9a0cd77c08644abbf3a69771c125c011",
|
||||
"filesize": 331808768,
|
||||
"direct_download_url": "https://akamai-ep.extremenetworks.com/Extreme_P/github-en/Virtual_VOSS/VOSSGNS3.8.2.0.0.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "VOSSGNS3.8.1.5.0.qcow2",
|
||||
"version": "8.1.5.0",
|
||||
@@ -56,6 +77,24 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "v8.4.0.0",
|
||||
"images": {
|
||||
"hda_disk_image": "VOSSGNS3.8.4.0.0.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "v8.3.0.0",
|
||||
"images": {
|
||||
"hda_disk_image": "VOSSGNS3.8.3.0.0.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "v8.2.0.0",
|
||||
"images": {
|
||||
"hda_disk_image": "VOSSGNS3.8.2.0.0.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "8.1.5.0",
|
||||
"images": {
|
||||
|
||||
@@ -27,6 +27,20 @@
|
||||
"options": "-smp 2 -cpu host"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "BIGIP-16.0.0.1-0.0.3.qcow2",
|
||||
"version": "16.0.0.1",
|
||||
"md5sum": "f153120d46e84c018c8ff78c6c7164bc",
|
||||
"filesize": 5393088512,
|
||||
"download_url": "https://downloads.f5.com/esd/serveDownload.jsp?path=/big-ip/big-ip_v16.x/16.0.0/english/16.0.0.1_virtual-edition/&sw=BIG-IP&pro=big-ip_v16.x&ver=16.0.0&container=16.0.0.1_Virtual-Edition&file=BIGIP-16.0.0.1-0.0.3.ALL.qcow2.zip"
|
||||
},
|
||||
{
|
||||
"filename": "BIGIP-16.0.0-0.0.12.qcow2",
|
||||
"version": "16.0.0",
|
||||
"md5sum": "c49cd2513e386f3259eb0ee6fe3bb502",
|
||||
"filesize": 5344722944,
|
||||
"download_url": "https://downloads.f5.com/esd/serveDownload.jsp?path=/big-ip/big-ip_v16.x/16.0.0/english/16.0.0_virtual-edition/&sw=BIG-IP&pro=big-ip_v16.x&ver=16.0.0&container=16.0.0_Virtual-Edition&file=BIGIP-16.0.0-0.0.12.ALL.qcow2.zip"
|
||||
},
|
||||
{
|
||||
"filename": "BIGIP-15.1.0.2-0.0.9.qcow2",
|
||||
"version": "15.1.0.2",
|
||||
@@ -163,6 +177,20 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "16.0.0.1",
|
||||
"images": {
|
||||
"hda_disk_image": "BIGIP-16.0.0.1-0.0.3.qcow2",
|
||||
"hdb_disk_image": "empty100G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "16.0.0",
|
||||
"images": {
|
||||
"hda_disk_image": "BIGIP-16.0.0-0.0.12.qcow2",
|
||||
"hdb_disk_image": "empty100G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "15.1.0.2",
|
||||
"images": {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 4,
|
||||
"ram": 1024,
|
||||
"ram": 4096,
|
||||
"hda_disk_interface": "virtio",
|
||||
"hdb_disk_interface": "virtio",
|
||||
"arch": "x86_64",
|
||||
@@ -26,6 +26,13 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "FAZ_VM64_KVM-v6-build2288-FORTINET.out.kvm.qcow2",
|
||||
"version": "6.4.5",
|
||||
"md5sum": "e220b48c6e86f8ddc660d578295051a9",
|
||||
"filesize": 152698880,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAZ_VM64_KVM-v6-build1183-FORTINET.out.kvm.qcow2",
|
||||
"version": "6.2.2",
|
||||
@@ -169,6 +176,13 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "6.4.5",
|
||||
"images": {
|
||||
"hda_disk_image": "FAZ_VM64_KVM-v6-build2288-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.2.2",
|
||||
"images": {
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "FGT_VM64_KVM-v6-build1828-FORTINET.out.kvm.qcow2",
|
||||
"version": "6.4.5",
|
||||
"md5sum": "dc064e16fa65461183544d8ddb5d19d9",
|
||||
"filesize": 36175872,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FGT_VM64_KVM-v6-build1010-FORTINET.out.kvm.qcow2",
|
||||
"version": "6.2.2",
|
||||
@@ -246,6 +253,13 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "6.4.5",
|
||||
"images": {
|
||||
"hda_disk_image": "FGT_VM64_KVM-v6-build1828-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.2.2",
|
||||
"images": {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 4,
|
||||
"ram": 1024,
|
||||
"ram": 2048,
|
||||
"hda_disk_interface": "virtio",
|
||||
"hdb_disk_interface": "virtio",
|
||||
"arch": "x86_64",
|
||||
@@ -26,6 +26,20 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "FMG_VM64_KVM-v6-build2288-FORTINET.out.kvm.qcow2",
|
||||
"version": "6.4.5",
|
||||
"md5sum": "bd2791984b03f55a6825297e83c6576a",
|
||||
"filesize": 117014528,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FMG_VM64_KVM-v6-build2253-FORTINET.out.kvm.qcow2",
|
||||
"version": "6.4.4",
|
||||
"md5sum": "3554a47fde2dc91d17eec16fd0dc10a3",
|
||||
"filesize": 116621312,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FMG_VM64_KVM-v6-build1183-FORTINET.out.kvm.qcow2",
|
||||
"version": "6.2.2",
|
||||
@@ -162,6 +176,20 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "6.4.5",
|
||||
"images": {
|
||||
"hda_disk_image": "FMG_VM64_KVM-v6-build2288-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.4.4",
|
||||
"images": {
|
||||
"hda_disk_image": "FMG_VM64_KVM-v6-build2253-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.2.2",
|
||||
"images": {
|
||||
|
||||
@@ -21,6 +21,14 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "frr-7.5.1.qcow2",
|
||||
"version": "7.5.1",
|
||||
"md5sum": "4b3ca0932a396b282ba35f102be1ed3b",
|
||||
"filesize": 51169280,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
|
||||
"direct_download_url": "http://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/frr-7.5.1.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "frr-7.3.1.qcow2",
|
||||
"version": "7.3.1",
|
||||
@@ -31,6 +39,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "7.5.1",
|
||||
"images": {
|
||||
"hda_disk_image": "frr-7.5.1.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "7.3.1",
|
||||
"images": {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "HuaWei AR1000v",
|
||||
"category": "router",
|
||||
"description": "Huawei AR1000V Virtual Router (Virtual CPE, vCPE) is an NFV product based on the industry-leading Huawei VRP platform. The product has rich business capabilities, integrating routing, switching, security, VPN, QoS and other functions, with software and hardware decoupling, Features such as easy business deployment and intelligent operation and maintenance can be applied to scenarios such as enterprise interconnection (SD-WAN) corporate headquarters (Hub point), POP point access, and cloud access.",
|
||||
"vendor_name": "HuaWei",
|
||||
"vendor_url": "https://www.huawei.com",
|
||||
"product_name": "HuaWei AR1000v",
|
||||
"product_url": "https://support.huawei.com/enterprise/en/routers/ar1000v-pid-21768212",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"availability": "service-contract",
|
||||
"maintainer": "none",
|
||||
"maintainer_email": "none",
|
||||
"usage": "Default user is super, default password is super.",
|
||||
"port_name_format": "GigabitEthernet0/0/{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 6,
|
||||
"ram": 4096,
|
||||
"cpus": 1,
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "cd",
|
||||
"kvm": "require",
|
||||
"options": "-machine type=pc,accel=kvm -vga std -usbdevice tablet -cpu host"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ar1k-V300R019C00SPC300.qcow2",
|
||||
"version": "V300R019C00SPC300",
|
||||
"md5sum": "5263e1d8964643a22c87f59ff14a5bdc",
|
||||
"filesize": 534904832,
|
||||
"download_url": "https://support.huawei.com/enterprise/en/routers/ar1000v-pid-21768212/software"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "V300R019C00SPC300",
|
||||
"images": {
|
||||
"hda_disk_image": "ar1k-V300R019C00SPC300.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "HuaWei CE12800",
|
||||
"category": "multilayer_switch",
|
||||
"description": "CE12800 series switches are high-performance core switches designed for data center networks and high-end campus networks. The switches provide stable, reliable, secure, and high-performance Layer 2/Layer 3 switching services, to help build an elastic, virtualized, agile, and high-quality network.",
|
||||
"vendor_name": "HuaWei",
|
||||
"vendor_url": "https://www.huawei.com",
|
||||
"product_name": "HuaWei CE12800",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"availability": "service-contract",
|
||||
"maintainer": "none",
|
||||
"maintainer_email": "none",
|
||||
"port_name_format": "GE1/0/{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 12,
|
||||
"ram": 2048,
|
||||
"cpus": 2,
|
||||
"hda_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"kvm": "require",
|
||||
"options": "-machine type=pc-1.0,accel=kvm -serial mon:stdio -nographic -nodefaults -rtc base=utc -cpu host"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ce12800-V200R005C10SPC607B607.qcow2",
|
||||
"version": "V200R005C10SPC607B607",
|
||||
"md5sum": "a6f2b358b299e2b5f0da2820ef315368",
|
||||
"filesize": 707002368,
|
||||
"download_url": "https://support.huawei.com/enterprise/en/switches/cloudengine-12800-pid-7542409/software"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "V200R005C10SPC607B607",
|
||||
"images": {
|
||||
"hda_disk_image": "ce12800-V200R005C10SPC607B607.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "HuaWei NE40E",
|
||||
"category": "router",
|
||||
"description": "Based on a 2T platform, the NetEngine 40E-X series provides the industry\u2019s highest capacity 2T routing line cards. Combining performance with low power consumption, innovative Internet Protocol (IP) hard pipe technology, and quick evolution capabilities, NetEngine 40E-X routers meet the low latency and high reliability requirements of business-critical services as well as mature Wide Area Network (WAN) Software-Defined Networking (SDN) solutions. They can serve as core nodes on enterprise WANs, access nodes on large-scale enterprise networks, interconnection and aggregation nodes on campus networks, and edge nodes on large-scale Internet Data Center (IDC) networks.",
|
||||
"vendor_name": "HuaWei",
|
||||
"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,
|
||||
"status": "experimental",
|
||||
"availability": "service-contract",
|
||||
"maintainer": "none",
|
||||
"maintainer_email": "none",
|
||||
"first_port_name": "eth0",
|
||||
"port_name_format": "Ethernet1/0/{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 12,
|
||||
"ram": 2048,
|
||||
"cpus": 2,
|
||||
"hda_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"kvm": "require",
|
||||
"options": "-machine type=pc-1.0,accel=kvm -serial mon:stdio -nographic -nodefaults -rtc base=utc -cpu host"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ne40e-V800R011C00SPC607B607.qcow2",
|
||||
"version": "V800R011C00SPC607B607",
|
||||
"md5sum": "2ac9c477e22a17860b76b3dc1d5aa119",
|
||||
"filesize": 496959488,
|
||||
"download_url": "https://support.huawei.com/enterprise/en/routers/ne40e-pid-15837/software"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "V800R011C00SPC607B607",
|
||||
"images": {
|
||||
"hda_disk_image": "ne40e-V800R011C00SPC607B607.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "HuaWei USG6000v",
|
||||
"category": "firewall",
|
||||
"description": "Huawei USG6000V is a virtual service gateway based on Network Functions Virtualization (NFV). It features high virtual resource usage and provides virtualized gateway services, such as vFW, vIPsec, vLB, vIPS, vAV, and vURL Remote Query.\nHuawei USG6000V is compatible with most mainstream virtual platforms. It provides standard APIs, together with the OpenStack cloud platform, SDN Controller, and MANO to achieve intelligent solutions for cloud security. This gateway meets flexible service customization requirements for frequent security service changes, elastic and on-demand resource allocation, visualized network management, and rapid rollout.",
|
||||
"vendor_name": "HuaWei",
|
||||
"vendor_url": "https://www.huawei.com",
|
||||
"product_name": "HuaWei USG6000v",
|
||||
"product_url": "https://e.huawei.com/en/products/enterprise-networking/security/firewall-gateway/usg6000v",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"availability": "service-contract",
|
||||
"maintainer": "none",
|
||||
"maintainer_email": "none",
|
||||
"usage": "Default password is admin. Default username and password for web is admin/Admin@123.",
|
||||
"first_port_name": "GigabitEthernet0/0/0",
|
||||
"port_name_format": "GigabitEthernet1/0/{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 6,
|
||||
"ram": 4096,
|
||||
"cpus": 2,
|
||||
"hda_disk_interface": "ide",
|
||||
"hdb_disk_interface": "ide",
|
||||
"hdc_disk_interface": "ide",
|
||||
"hdd_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "dc",
|
||||
"kvm": "require",
|
||||
"options": "-machine type=pc,accel=kvm -vga std -usbdevice tablet"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "usg6kv-v2-V500R001C10.qcow2",
|
||||
"version": "V500R001C10",
|
||||
"md5sum": "07f87aaa4f4d8b9a713d90eb32f89111",
|
||||
"filesize": 737476608,
|
||||
"download_url": "https://support.huawei.com/enterprise/en/security/usg6000v-pid-21431620/software"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "V500R001C10",
|
||||
"images": {
|
||||
"hda_disk_image": "usg6kv-v2-V500R001C10.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "ipxe",
|
||||
"category": "guest",
|
||||
"description": "boot guest from network via iPXE",
|
||||
"vendor_name": "Linux",
|
||||
"vendor_url": "http://gns3.com/",
|
||||
"documentation_url": "http://ipxe.org",
|
||||
"product_name": "iPXE netboot",
|
||||
"product_url": "http://ipxe.org/",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "x86_64 guest booted from network via iPXE. If you need latest ipxe version - download, attach and boot iso from http://boot.ipxe.org/ipxe.iso. Don't forget to adjust memory according guest requirements. If guest is linux, you can add serial console options to kernel arguments.",
|
||||
"symbol": "linux_guest.svg",
|
||||
"port_name_format": "eth{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 1,
|
||||
"ram": 1024,
|
||||
"hda_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "n",
|
||||
"kvm": "allow",
|
||||
"options": "-nographic"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "empty8G.qcow2",
|
||||
"version": "1.0",
|
||||
"md5sum": "f1d2c25b6990f99bd05b433ab603bdb4",
|
||||
"filesize": 197120,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/",
|
||||
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty8G.qcow2/download"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "1.0",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -46,24 +46,6 @@
|
||||
"md5sum": "25322c2caf542059de72e9adbec1fb68",
|
||||
"filesize": 10485760
|
||||
},
|
||||
{
|
||||
"filename": "junos-vmx-x86-64-19.3R1.8.qcow2",
|
||||
"version": "19.3R1.8-KVM",
|
||||
"md5sum": "cd14a6884edeb6b337d3c2be02241c63",
|
||||
"filesize": 1435238400
|
||||
},
|
||||
{
|
||||
"filename": "vmxhdd-19.3R1.8.img",
|
||||
"version": "19.3R1.8-KVM",
|
||||
"md5sum": "ae26e0f32605a53a5c85342bad677c9f",
|
||||
"filesize": 197120
|
||||
},
|
||||
{
|
||||
"filename": "metadata-usb-re-19.3R1.8.img",
|
||||
"version": "19.3R1.8-KVM",
|
||||
"md5sum": "3c66c4657773a0cd2b38ffd84115446a",
|
||||
"filesize": 10485760
|
||||
},
|
||||
{
|
||||
"filename": "junos-vmx-x86-64-17.4R1.16.qcow2",
|
||||
"version": "17.4R1.16-KVM",
|
||||
@@ -365,14 +347,6 @@
|
||||
"hdc_disk_image": "metadata-usb-re-20.2R1.10.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "19.3R1.8-KVM",
|
||||
"images": {
|
||||
"hda_disk_image": "junos-vmx-x86-64-19.3R1.8.qcow2",
|
||||
"hdb_disk_image": "vmxhdd-19.3R1.8.img",
|
||||
"hdc_disk_image": "metadata-usb-re-19.3R1.8.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "17.4R1.16-KVM",
|
||||
"images": {
|
||||
|
||||
@@ -25,6 +25,20 @@
|
||||
"options": "-smp 2"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "junos-media-vsrx-x86-64-vmdisk-20.4R1.12.qcow2",
|
||||
"version": "20.4R1",
|
||||
"md5sum": "a445304c6f710d6d5401b486ef68cd20",
|
||||
"filesize": 6796738560,
|
||||
"download_url": "https://www.juniper.net/us/en/dm/free-vsrx-trial/"
|
||||
},
|
||||
{
|
||||
"filename": "junos-vsrx3-x86-64-20.4R1.12.qcow2",
|
||||
"version": "20.4R1 3.0",
|
||||
"md5sum": "0e7a44a56c0326908fcbdc70451e08f5",
|
||||
"filesize": 942211072,
|
||||
"download_url": "https://www.juniper.net/us/en/dm/free-vsrx-trial/"
|
||||
},
|
||||
{
|
||||
"filename": "junos-media-vsrx-x86-64-vmdisk-19.3R1.8.qcow2",
|
||||
"version": "19.3R1",
|
||||
@@ -32,6 +46,13 @@
|
||||
"filesize": 5185142784,
|
||||
"download_url": "https://www.juniper.net/us/en/dm/free-vsrx-trial/"
|
||||
},
|
||||
{
|
||||
"filename": "junos-vsrx3-x86-64-19.3R1.8.qcow2",
|
||||
"version": "19.3R1 3.0",
|
||||
"md5sum": "b94d6e5b38737af09c5c9f49c623b69b",
|
||||
"filesize": 834928640,
|
||||
"download_url": "https://www.juniper.net/us/en/dm/free-vsrx-trial/"
|
||||
},
|
||||
{
|
||||
"filename": "junos-media-vsrx-vmdisk-18.1R1.9.qcow2",
|
||||
"version": "18.1R1",
|
||||
@@ -39,6 +60,13 @@
|
||||
"filesize": 4418961408,
|
||||
"download_url": "https://www.juniper.net/us/en/dm/free-vsrx-trial/"
|
||||
},
|
||||
{
|
||||
"filename": "junos-vsrx3-x86-64-18.4R3.3.qcow2",
|
||||
"version": "18.4R3 3.0",
|
||||
"md5sum": "bb1dec15bb047446f80d85a129cb57c6",
|
||||
"filesize": 764805120,
|
||||
"download_url": "https://www.juniper.net/us/en/dm/free-vsrx-trial/"
|
||||
},
|
||||
{
|
||||
"filename": "media-vsrx-vmdisk-17.4R1.16.qcow2",
|
||||
"version": "17.4R1",
|
||||
@@ -153,18 +181,42 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "20.4R1",
|
||||
"images": {
|
||||
"hda_disk_image": "junos-media-vsrx-x86-64-vmdisk-20.4R1.12.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "20.4R1 3.0",
|
||||
"images": {
|
||||
"hda_disk_image": "junos-vsrx3-x86-64-20.4R1.12.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "19.3R1",
|
||||
"images": {
|
||||
"hda_disk_image": "junos-media-vsrx-x86-64-vmdisk-19.3R1.8.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "19.3R1 3.0",
|
||||
"images": {
|
||||
"hda_disk_image": "junos-vsrx3-x86-64-19.3R1.8.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "18.1R1",
|
||||
"images": {
|
||||
"hda_disk_image": "junos-media-vsrx-vmdisk-18.1R1.9.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "18.4R3 3.0",
|
||||
"images": {
|
||||
"hda_disk_image": "junos-vsrx3-x86-64-18.4R3.3.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "17.4R1",
|
||||
"images": {
|
||||
|
||||
@@ -23,101 +23,109 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "kali-linux-2021.1-live-amd64.iso",
|
||||
"version": "2021.1",
|
||||
"md5sum": "3a3716fef866e5c29a1c1ccfc94264b5",
|
||||
"filesize": 3591385088,
|
||||
"download_url": "http://cdimage.kali.org/kali-2021.1/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2021.1/kali-linux-2021.1-live-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2019.3-amd64.iso",
|
||||
"version": "2019.3",
|
||||
"md5sum": "9c6fb00558f78ed06992d89f745ef975",
|
||||
"filesize": 3037736960,
|
||||
"download_url": "https://www.kali.org/downloads/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2019.3/kali-linux-2019.3-amd64.iso"
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2019.3",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2019.3/kali-linux-2019.3-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2019.2-amd64.iso",
|
||||
"version": "2019.2",
|
||||
"md5sum": "0f89b6225d7ea9c18682f7cc541c1179",
|
||||
"filesize": 3353227264,
|
||||
"download_url": "https://www.kali.org/downloads/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2019.2/kali-linux-2019.2-amd64.iso"
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2019.2",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2019.2/kali-linux-2019.2-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-mate-2019.2-amd64.iso",
|
||||
"version": "2019.2 (MATE)",
|
||||
"md5sum": "fec8dd7009f932c51a74323df965a709",
|
||||
"filesize": 3313217536,
|
||||
"download_url": "https://www.kali.org/downloads/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2019.2/kali-linux-mate-2019.2-amd64.iso"
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2019.2",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2019.2/kali-linux-mate-2019.2-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2019.1a-amd64.iso",
|
||||
"version": "2019.1a",
|
||||
"md5sum": "58c6111ed0be1919ea87267e7e65ab0f",
|
||||
"filesize": 3483873280,
|
||||
"download_url": "https://www.kali.org/downloads/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2019.1a/kali-linux-2019.1a-amd64.iso"
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2019.1a",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2019.1a/kali-linux-2019.1a-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2018.4-amd64.iso",
|
||||
"version": "2018.4",
|
||||
"md5sum": "1b2d598bb8d2003e6207c119c0ba42fe",
|
||||
"filesize": 3139436544,
|
||||
"download_url": "https://www.kali.org/downloads/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2018.4/kali-linux-2018.4-amd64.iso"
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2018.4",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2018.4/kali-linux-2018.4-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2018.3a-amd64.iso",
|
||||
"version": "2018.3a",
|
||||
"md5sum": "2da675d016bd690c05e180e33aa98b94",
|
||||
"filesize": 3192651776,
|
||||
"download_url": "https://www.kali.org/downloads/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2018.3a/kali-linux-2018.3a-amd64.iso"
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2018.3a",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2018.3a/kali-linux-2018.3a-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2018.1-amd64.iso",
|
||||
"version": "2018.1",
|
||||
"md5sum": "a3feb90df5b71b3c7f4a02bdddf221d7",
|
||||
"filesize": 3028500480,
|
||||
"download_url": "https://www.kali.org/downloads/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2018.1/kali-linux-2018.1-amd64.iso"
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2018.1",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2018.1/kali-linux-2018.1-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2017.3-amd64.iso",
|
||||
"version": "2017.3",
|
||||
"md5sum": "b465580c897e94675ac1daf031fa66b9",
|
||||
"filesize": 2886402048,
|
||||
"download_url": "http://cdimage.kali.org/kali-2017.3/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2017.3/kali-linux-2017.3-amd64.iso"
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2017.3/",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2017.3/kali-linux-2017.3-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2017.2-amd64.iso",
|
||||
"version": "2017.2",
|
||||
"md5sum": "541654f8f818450dc0db866a0a0f6eec",
|
||||
"filesize": 3020619776,
|
||||
"download_url": "http://cdimage.kali.org/kali-2017.2/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2017.2/kali-linux-2017.2-amd64.iso"
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2017.2/",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2017.2/kali-linux-2017.2-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2017.1-amd64.iso",
|
||||
"version": "2017.1",
|
||||
"md5sum": "c8e742283929d7a12dbe7c58e398ff08",
|
||||
"filesize": 2794307584,
|
||||
"download_url": "http://cdimage.kali.org/kali-2017.1/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2017.1/kali-linux-2017.1-amd64.iso"
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2017.1/",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2017.1/kali-linux-2017.1-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2016.2-amd64.iso",
|
||||
"version": "2016.2",
|
||||
"md5sum": "3d163746bc5148e61ad689d94bc263f9",
|
||||
"filesize": 3076767744,
|
||||
"download_url": "http://cdimage.kali.org/kali-2016.2/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2016.2/kali-linux-2016.2-amd64.iso"
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2016.2/",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2016.2/kali-linux-2016.2-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2016.1-amd64.iso",
|
||||
"version": "2016.1",
|
||||
"md5sum": "2e1230dc14036935b3279dfe3e49ad39",
|
||||
"filesize": 2945482752,
|
||||
"download_url": "http://cdimage.kali.org/kali-2016.1/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2016.1/kali-linux-2016.1-amd64.iso"
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2016.1/",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2016.1/kali-linux-2016.1-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2.0-amd64.iso",
|
||||
@@ -137,6 +145,13 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "2021.1",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2021.1-live-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2019.3",
|
||||
"images": {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "mcjoin",
|
||||
"category": "guest",
|
||||
"description": "mcjoin is a very simple and easy-to-use tool to test IPv4 and IPv6 multicast.",
|
||||
"vendor_name": "Joachim Nilsson",
|
||||
"vendor_url": "https://github.com/troglobit",
|
||||
"product_name": "mcjoin",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"symbol": "linux_guest.svg",
|
||||
"docker": {
|
||||
"adapters": 1,
|
||||
"image": "troglobit/mcjoin:latest",
|
||||
"console_type": "telnet"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "Nokia vSIM",
|
||||
"category": "router",
|
||||
"description": "The Nokia Virtualized 7750 SR and 7950 XRS Simulator (vSIM) is a Virtualized Network Function (VNF) that simulates the control, management, and forwarding functions of a 7750 SR or 7950 XRS router. The vSIM runs the same Service Router Operating System (SR OS) as 7750 SR and 7950 XRS hardware-based routers and, therefore, has the same feature set and operational behavior as those platforms.",
|
||||
"vendor_name": "Nokia",
|
||||
"vendor_url": "https://www.nokia.com/networks/",
|
||||
"documentation_url": "https://documentation.nokia.com/",
|
||||
"product_name": "Nokia vSIM",
|
||||
"product_url": "https://www.nokia.com/networks/products/virtualized-service-router/",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"maintainer": "Vinicius Rocha",
|
||||
"maintainer_email": "viniciusatr@gmail.com",
|
||||
"usage": "Login is admin and password is admin. \n\nWe are using one IOM with one MDA 12x100G (w/ breakout).\n\nYou must add your license: file vi cf3:license.txt",
|
||||
"first_port_name": "A/1",
|
||||
"port_name_format": "1/1/{port1}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 13,
|
||||
"ram": 4096,
|
||||
"cpus": 2,
|
||||
"hda_disk_interface": "virtio",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"kvm": "require",
|
||||
"options": "-nographic -smbios type=1,product=TIMOS:license-file=cf3:license.txt\\ slot=A\\ chassis=SR-1\\ card=cpm-1\\ mda/1=me12-100gb-qsfp28"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "sros-vsr-21.7.R1.qcow2",
|
||||
"version": "21.7.R1",
|
||||
"md5sum": "7eed38c01350ebaf9c6105e26ce5307e",
|
||||
"filesize": 568655872,
|
||||
"download_url": "https://customer.nokia.com/support/s/",
|
||||
"compression": "zip"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "21.7.R1",
|
||||
"images": {
|
||||
"hda_disk_image": "sros-vsr-21.7.R1.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3,16 +3,18 @@
|
||||
"category": "guest",
|
||||
"description": "ntopng is the next generation version of the original ntop, a network traffic probe that shows the network usage, similar to what the popular top Unix command does. ntopng is based on libpcap and it has been written in a portable way in order to virtually run on every Unix platform, MacOSX and on Windows as well. ntopng users can use a a web browser to navigate through ntop (that acts as a web server) traffic information and get a dump of the network status. In the latter case, ntopng can be seen as a simple RMON-like agent with an embedded web interface.",
|
||||
"vendor_name": "ntop",
|
||||
"vendor_url": "http://www.ntop.org/",
|
||||
"vendor_url": "https://www.ntop.org/",
|
||||
"documentation_url": "https://www.ntop.org/guides/ntopng/",
|
||||
"product_name": "ntopng",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "In the web interface login as admin/admin",
|
||||
"usage": "In the web interface login as admin/admin\n\nPersistent configuration:\n- Add \"/var/lib/redis\" as an additional persistent directory.\n- Use \"redis-cli save\" in an auxiliary console to save the configuration.",
|
||||
"docker": {
|
||||
"adapters": 1,
|
||||
"image": "lucaderi/ntopng-docker:latest",
|
||||
"image": "ntop/ntopng:stable",
|
||||
"start_command": "--dns-mode 2 --interface eth0",
|
||||
"console_type": "http",
|
||||
"console_http_port": 3000,
|
||||
"console_http_path": "/"
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"name": "OpenMediaVault",
|
||||
"category": "guest",
|
||||
"description": "openmediavault is the next generation network attached storage (NAS) solution based on Debian Linux. It contains services like SSH, (S)FTP, SMB/CIFS, DAAP media server, RSync, BitTorrent client and many more.",
|
||||
"vendor_name": "Volker Theile",
|
||||
"vendor_url": "https://www.openmediavault.org/",
|
||||
"documentation_url": "hhttps://docs.openmediavault.org",
|
||||
"product_name": "OpenMediaVault",
|
||||
"product_url": "https://www.openmediavault.org/",
|
||||
"registry_version": 4,
|
||||
"status": "stable",
|
||||
"maintainer": "Savio D'souza",
|
||||
"maintainer_email": "savio2002@yahoo.in",
|
||||
"usage": "Install OS to first Disk, poweroff, eject iso.\nAdd empty30G.qcow2 to Secondary master and slave this way you will get 3 hard disks for storage.\nDefault WUI credentials are admin:openmediavault.",
|
||||
"port_name_format": "eth{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 1,
|
||||
"ram": 2048,
|
||||
"hda_disk_interface": "sata",
|
||||
"hdb_disk_interface": "sata",
|
||||
"arch": "x86_64",
|
||||
"console_type": "vnc",
|
||||
"boot_priority": "dc",
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "openmediavault_5.6.13-amd64.iso",
|
||||
"version": "5.6.13",
|
||||
"md5sum": "f08b41a5111fffca0355d53e26ec47ab",
|
||||
"filesize": 652214272,
|
||||
"download_url": "https://www.openmediavault.org/download.html",
|
||||
"direct_download_url": "https://sourceforge.net/projects/openmediavault/files/5.6.13/openmediavault_5.6.13-amd64.iso/download"
|
||||
},
|
||||
{
|
||||
"filename": "openmediavault_5.5.11-amd64.iso",
|
||||
"version": "5.5.11",
|
||||
"md5sum": "76baad8e13dd49bee9b4b4a6936b7296",
|
||||
"filesize": 608174080,
|
||||
"download_url": "https://www.openmediavault.org/download.html",
|
||||
"direct_download_url": "https://sourceforge.net/projects/openmediavault/files/5.5.11/openmediavault_5.5.11-amd64.iso/download"
|
||||
},
|
||||
{
|
||||
"filename": "empty30G.qcow2",
|
||||
"version": "1.0",
|
||||
"md5sum": "3411a599e822f2ac6be560a26405821a",
|
||||
"filesize": 197120,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/",
|
||||
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty30G.qcow2/download"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "5.6.13",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2",
|
||||
"cdrom_image": "openmediavault_5.6.13-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.5.11",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2",
|
||||
"cdrom_image": "openmediavault_5.5.11-amd64.iso"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "User root, password gns3",
|
||||
"first_port_name": "fxp0",
|
||||
"first_port_name": "em0",
|
||||
"port_name_format": "em{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
|
||||
@@ -22,6 +22,51 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "openwrt-21.02.0-x86-64-generic-ext4-combined.img",
|
||||
"version": "21.02.0",
|
||||
"md5sum": "1ba2a5c5c05e592c36a469a8ecd3bcf5",
|
||||
"filesize": 126353408,
|
||||
"download_url": "https://downloads.openwrt.org/releases/21.02.0/targets/x86/64/",
|
||||
"direct_download_url": "https://downloads.openwrt.org/releases/21.02.0/targets/x86/64/openwrt-21.02.0-x86-64-generic-ext4-combined.img.gz",
|
||||
"compression": "gzip"
|
||||
},
|
||||
{
|
||||
"filename": "openwrt-19.07.8-x86-64-combined-ext4.img",
|
||||
"version": "19.07.8",
|
||||
"md5sum": "a9d9776a96968a2042484330f285cae3",
|
||||
"filesize": 285736960,
|
||||
"download_url": "https://downloads.openwrt.org/releases/19.07.8/targets/x86/64/",
|
||||
"direct_download_url": "https://downloads.openwrt.org/releases/19.07.8/targets/x86/64/openwrt-19.07.8-x86-64-combined-ext4.img",
|
||||
"compression": "gzip"
|
||||
},
|
||||
{
|
||||
"filename": "openwrt-19.07.7-x86-64-combined-ext4.img",
|
||||
"version": "19.07.7",
|
||||
"md5sum": "0cfa752fab87014419ab00b18a6cc5a6",
|
||||
"filesize": 285736960,
|
||||
"download_url": "https://downloads.openwrt.org/releases/19.07.7/targets/x86/64/",
|
||||
"direct_download_url": "https://downloads.openwrt.org/releases/19.07.7/targets/x86/64/openwrt-19.07.7-x86-64-combined-ext4.img.gz",
|
||||
"compression": "gzip"
|
||||
},
|
||||
{
|
||||
"filename": "openwrt-19.07.6-x86-64-combined-ext4.img",
|
||||
"version": "19.07.6",
|
||||
"md5sum": "db0d48f47917684f6ce9c8430d90bb8a",
|
||||
"filesize": 285736960,
|
||||
"download_url": "https://downloads.openwrt.org/releases/19.07.6/targets/x86/64/",
|
||||
"direct_download_url": "https://downloads.openwrt.org/releases/19.07.6/targets/x86/64/openwrt-19.07.6-x86-64-combined-ext4.img.gz",
|
||||
"compression": "gzip"
|
||||
},
|
||||
{
|
||||
"filename": "openwrt-19.07.5-x86-64-combined-ext4.img",
|
||||
"version": "19.07.5",
|
||||
"md5sum": "20167cfbb8d51adad9e251f4cd3508fe",
|
||||
"filesize": 285736960,
|
||||
"download_url": "https://downloads.openwrt.org/releases/19.07.5/targets/x86/64/",
|
||||
"direct_download_url": "https://downloads.openwrt.org/releases/19.07.5/targets/x86/64/openwrt-19.07.5-x86-64-combined-ext4.img.gz",
|
||||
"compression": "gzip"
|
||||
},
|
||||
{
|
||||
"filename": "openwrt-19.07.4-x86-64-combined-ext4.img",
|
||||
"version": "19.07.4",
|
||||
@@ -141,6 +186,36 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "21.02.0",
|
||||
"images": {
|
||||
"hda_disk_image": "openwrt-21.02.0-x86-64-generic-ext4-combined.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "19.07.8",
|
||||
"images": {
|
||||
"hda_disk_image": "openwrt-19.07.8-x86-64-combined-ext4.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "19.07.7",
|
||||
"images": {
|
||||
"hda_disk_image": "openwrt-19.07.7-x86-64-combined-ext4.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "19.07.6",
|
||||
"images": {
|
||||
"hda_disk_image": "openwrt-19.07.6-x86-64-combined-ext4.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "19.07.5",
|
||||
"images": {
|
||||
"hda_disk_image": "openwrt-19.07.5-x86-64-combined-ext4.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "19.07.4",
|
||||
"images": {
|
||||
|
||||
@@ -25,31 +25,31 @@
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "OPNsense-18.1.6-OpenSSL-nano-amd64.img",
|
||||
"version": "18.1.6",
|
||||
"md5sum": "042f328380ad0c8008759c43435e8843",
|
||||
"filesize": 272003136,
|
||||
"download_url": "https://opnsense.c0urier.net/releases/18.1/"
|
||||
"filename": "OPNsense-20.7-OpenSSL-nano-amd64.img",
|
||||
"version": "20.7",
|
||||
"md5sum": "453e505e9526d4a0a3d5208efdd13b1a",
|
||||
"filesize": 3221225472,
|
||||
"download_url": "https://opnsense.c0urier.net/releases/20.7/"
|
||||
},
|
||||
{
|
||||
"filename": "OPNsense-17.7.5-OpenSSL-nano-amd64.img",
|
||||
"version": "17.7.5",
|
||||
"md5sum": "6ec5b7f99cc727f904bbf2aaadcab0b8",
|
||||
"filesize": 237038601,
|
||||
"download_url": "https://opnsense.c0urier.net/releases/17.7/"
|
||||
"filename": "OPNsense-19.7-OpenSSL-nano-amd64.img",
|
||||
"version": "19.7",
|
||||
"md5sum": "a15a00cfa2de45791d6bc230d8469dc7",
|
||||
"filesize": 3221225472,
|
||||
"download_url": "https://opnsense.c0urier.net/releases/19.7/"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "18.1.6",
|
||||
"name": "20.7",
|
||||
"images": {
|
||||
"hda_disk_image": "OPNsense-18.1.6-OpenSSL-nano-amd64.img"
|
||||
"hda_disk_image": "OPNsense-20.7-OpenSSL-nano-amd64.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "17.7.5",
|
||||
"name": "19.7",
|
||||
"images": {
|
||||
"hda_disk_image": "OPNsense-17.7.5-OpenSSL-nano-amd64.img"
|
||||
"hda_disk_image": "OPNsense-19.7-OpenSSL-nano-amd64.img"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
{
|
||||
"name": "Ostinato",
|
||||
"category": "guest",
|
||||
"description": "Ostinato is an open-source, cross-platform network packet crafter/traffic generator and analyzer with a friendly GUI. Craft and send packets of several streams with different protocols at different rates.",
|
||||
"description": "Packet crafter and traffic generator for network engineers",
|
||||
"vendor_name": "Ostinato",
|
||||
"vendor_url": "http://ostinato.org/",
|
||||
"documentation_url": "http://ostinato.org/docs.html",
|
||||
"vendor_url": "https://ostinato.org/",
|
||||
"documentation_url": "https://ostinato.org/docs",
|
||||
"product_name": "Ostinato",
|
||||
"product_url": "http://ostinato.org/",
|
||||
"registry_version": 3,
|
||||
"status": "experimental",
|
||||
"maintainer": "Bernhard Ehlers",
|
||||
"maintainer_email": "be@bernhard-ehlers.de",
|
||||
"usage": "Use interfaces starting with eth1 as traffic interfaces, eth0 is only for the (optional) management of the server/drone.",
|
||||
"symbol": "ostinato-3d-icon.svg",
|
||||
"port_name_format": "eth{0}",
|
||||
"product_url": "https://ostinato.org/",
|
||||
"registry_version": 4,
|
||||
"status": "stable",
|
||||
"availability": "service-contract",
|
||||
"maintainer": "Srivats P",
|
||||
"maintainer_email": "support@ostinato.org",
|
||||
"symbol": ":/symbols/affinity/circle/gray/cog.svg",
|
||||
"first_port_name": "eth0/mgmt",
|
||||
"port_name_format": "eth{port1}",
|
||||
"linked_clone": true,
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 4,
|
||||
"ram": 256,
|
||||
"hda_disk_interface": "ide",
|
||||
"cpus": 2,
|
||||
"hda_disk_interface": "sata",
|
||||
"arch": "i386",
|
||||
"console_type": "vnc",
|
||||
"kvm": "allow",
|
||||
@@ -26,33 +29,18 @@
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ostinato-0.9-1.qcow2",
|
||||
"version": "0.9",
|
||||
"md5sum": "00b4856ec9fffbcbcab7a8f757355d69",
|
||||
"filesize": 101646336,
|
||||
"download_url": "http://www.bernhard-ehlers.de/projects/ostinato4gns3/index.html",
|
||||
"direct_download_url": "http://www.bernhard-ehlers.de/projects/ostinato4gns3/ostinato-0.9-1.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "ostinato-0.8-1.qcow2",
|
||||
"version": "0.8",
|
||||
"md5sum": "12e990ba695103cfac82f8771b8015d4",
|
||||
"filesize": 57344000,
|
||||
"download_url": "http://www.bernhard-ehlers.de/projects/ostinato4gns3/index.html",
|
||||
"direct_download_url": "http://www.bernhard-ehlers.de/projects/ostinato4gns3/ostinato-0.8-1.qcow2"
|
||||
"version": "1.1",
|
||||
"filename": "ostinatostd-1.1-1.qcow2",
|
||||
"filesize": 134217728,
|
||||
"md5sum": "aa027e83cefea1c38d0102eb2f28956e",
|
||||
"download_url": "https://ostinato.org/pricing/gns3"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "0.9",
|
||||
"name": "1.1",
|
||||
"images": {
|
||||
"hda_disk_image": "ostinato-0.9-1.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "0.8",
|
||||
"images": {
|
||||
"hda_disk_image": "ostinato-0.8-1.qcow2"
|
||||
"hda_disk_image": "ostinatostd-1.1-1.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"name": "Puppy Linux",
|
||||
"category": "guest",
|
||||
"description": "Puppy Linux is a unique family of Linux distributions meant for the home-user computers. It was originally created by Barry Kauler in 2003.",
|
||||
"vendor_name": "Puppy Linux",
|
||||
"vendor_url": "http://puppylinux.com/",
|
||||
"documentation_url": "http://wikka.puppylinux.com/HomePage",
|
||||
"product_name": "Puppy Linux",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "Savio D'souza",
|
||||
"maintainer_email": "savio2002@yahoo.in",
|
||||
"usage": "No Password by default\nRun installer & install to local disk\nEject the ISO and reboot.",
|
||||
"port_name_format": "eth{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 1,
|
||||
"ram": 256,
|
||||
"arch": "x86_64",
|
||||
"console_type": "vnc",
|
||||
"boot_priority": "cd",
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "fossapup64-9.5.iso",
|
||||
"version": "9.5",
|
||||
"md5sum": "6a45e7a305b7d3172ebd9eab5ca460e4",
|
||||
"filesize": 428867584,
|
||||
"download_url": "http://puppylinux.com/index.html",
|
||||
"direct_download_url": "http://distro.ibiblio.org/puppylinux/puppy-fossa/fossapup64-9.5.iso"
|
||||
},
|
||||
{
|
||||
"filename": "bionicpup64-8.0-uefi.iso",
|
||||
"version": "8.0",
|
||||
"md5sum": "e31ddba0e6006021c157cb5a5b65ad5f",
|
||||
"filesize": 371195904,
|
||||
"download_url": "http://puppylinux.com/index.html",
|
||||
"direct_download_url": "http://distro.ibiblio.org/puppylinux/puppy-bionic/bionicpup64/bionicpup64-8.0-uefi.iso"
|
||||
},
|
||||
{
|
||||
"filename": "xenialpup64-7.5-uefi.iso",
|
||||
"version": "7.5",
|
||||
"md5sum": "4502bb9693bd72fb5dcfb86a2ce8255d",
|
||||
"filesize": 346030080,
|
||||
"download_url": "http://puppylinux.com/index.html",
|
||||
"direct_download_url": "http://distro.ibiblio.org/puppylinux/puppy-xenial/64/xenialpup64-7.5-uefi.iso"
|
||||
},
|
||||
{
|
||||
"filename": "empty8G.qcow2",
|
||||
"version": "1.0",
|
||||
"md5sum": "f1d2c25b6990f99bd05b433ab603bdb4",
|
||||
"filesize": 197120,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/",
|
||||
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty8G.qcow2/download"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "9.5",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "fossapup64-9.5.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "8.0",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "bionicpup64-8.0-uefi.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "7.5",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "xenialpup64-7.5-uefi.iso"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
"vendor_url": "https://www.raspberrypi.org",
|
||||
"product_name": "Raspberry Pi Desktop",
|
||||
"product_url": "https://www.raspberrypi.org/downloads/raspberry-pi-desktop/",
|
||||
"registry_version": 3,
|
||||
"registry_version": 4,
|
||||
"status": "stable",
|
||||
"availability": "free",
|
||||
"maintainer": "Brent Stewart",
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"name": "RHEL",
|
||||
"category": "guest",
|
||||
"description": "Red Hat Enterprise Linux Server provides core operating system functions and capabilities for application infrastructure.",
|
||||
"vendor_name": "Red Hat",
|
||||
"vendor_url": "https://redhat.com",
|
||||
"documentation_url": "https://access.redhat.com/solutions/641193",
|
||||
"product_name": "Red Hat Enterprise Linux KVM Guest Image",
|
||||
"product_url": "https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux",
|
||||
"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---8/8.3/x86_64/product-software attach/customize cloud-init.iso and start.\nusername: cloud-user\npassword: redhat",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 1,
|
||||
"ram": 1024,
|
||||
"hda_disk_interface": "virtio",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "c",
|
||||
"kvm": "require",
|
||||
"options": "-nographic"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "rhel-8.3-x86_64-kvm.qcow2",
|
||||
"version": "8.3",
|
||||
"md5sum": "dd554c059e0910379fff88f677f4a4b3",
|
||||
"filesize": 1316683776,
|
||||
"download_url": "https://access.redhat.com/downloads/content/479/ver=/rhel---8/8.3/x86_64/product-software"
|
||||
},
|
||||
{
|
||||
"filename": "rhel-server-7.9-x86_64-kvm.qcow2",
|
||||
"version": "7.9",
|
||||
"md5sum": "8d6669b3e2bb8df15b9b4280936cf950",
|
||||
"filesize": 827777024,
|
||||
"download_url": "https://access.redhat.com/downloads/content/69/ver=/rhel---7/7.9/x86_64/product-software"
|
||||
},
|
||||
{
|
||||
"filename": "rhel-server-6.10-update-11-x86_64-kvm.qcow2",
|
||||
"version": "6.10",
|
||||
"md5sum": "6d672026d3a0eae794a677a18287f9c0",
|
||||
"filesize": 341442560,
|
||||
"download_url": "https://access.redhat.com/downloads/content/69/ver=/rhel---6/6.10/x86_64/product-software"
|
||||
},
|
||||
{
|
||||
"filename": "rhel-cloud-init.iso",
|
||||
"version": "1.0",
|
||||
"md5sum": "421745b0d13615ecd48696f98d8b6352",
|
||||
"filesize": 374784,
|
||||
"download_url": "https://gitlab.com/neyder/rhel-cloud-init/raw/master/rhel-cloud-init.iso"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "8.3",
|
||||
"images": {
|
||||
"hda_disk_image": "rhel-8.3-x86_64-kvm.qcow2",
|
||||
"cdrom_image": "rhel-cloud-init.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "7.9",
|
||||
"images": {
|
||||
"hda_disk_image": "rhel-server-7.9-x86_64-kvm.qcow2",
|
||||
"cdrom_image": "rhel-cloud-init.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.10",
|
||||
"images": {
|
||||
"hda_disk_image": "rhel-server-6.10-update-11-x86_64-kvm.qcow2",
|
||||
"cdrom_image": "rhel-cloud-init.iso"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "RockyLinux",
|
||||
"category": "guest",
|
||||
"description": "Rocky Linux is a community enterprise operating system designed to be 100% bug-for-bug compatible with Red Hat Enterprise Linux (RHEL).",
|
||||
"vendor_name": "Rocky Enterprise Software Foundation",
|
||||
"vendor_url": "https://rockylinux.org",
|
||||
"documentation_url": "https://docs.rockylinux.org",
|
||||
"product_name": "Rocky Linux",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"maintainer": "Bernhard Ehlers",
|
||||
"maintainer_email": "none@b-ehlers.de",
|
||||
"usage": "Username:\trockylinux\nPassword:\trockylinux\nTo become root, use \"sudo su\".\n\nTo improve performance, increase RAM and vCPUs in the VM settings.",
|
||||
"symbol": "linux_guest.svg",
|
||||
"port_name_format": "ens{port4}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 1,
|
||||
"ram": 1536,
|
||||
"hda_disk_interface": "sata",
|
||||
"arch": "x86_64",
|
||||
"console_type": "vnc",
|
||||
"kvm": "require",
|
||||
"options": "-usbdevice tablet"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "RockyLinux_8.4_VMG_LinuxVMImages.COM.vmdk",
|
||||
"version": "8.4",
|
||||
"md5sum": "3452d5b0fbb4cdcf3ac6fe8de8d0ac08",
|
||||
"filesize": 5273878528,
|
||||
"download_url": "https://www.linuxvmimages.com/images/rockylinux-8",
|
||||
"direct_download_url": "https://sourceforge.net/projects/linuxvmimages/files/VMware/R/rockylinux/8/RockyLinux_8.4_VMM.7z/download",
|
||||
"compression": "7z"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "8.4",
|
||||
"images": {
|
||||
"hda_disk_image": "RockyLinux_8.4_VMG_LinuxVMImages.COM.vmdk"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "StoneWork",
|
||||
"category": "router",
|
||||
"description": "StoneWork is VPP and Ligato based routing platform",
|
||||
"vendor_name": "Pantheon.tech StoneWork router",
|
||||
"vendor_url": "https://pantheon.tech/",
|
||||
"documentation_url": "https://pantheon.tech/documentation-stonework-gns3/",
|
||||
"product_name": "StoneWork",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"availability": "free",
|
||||
"maintainer": "Julius Milan",
|
||||
"maintainer_email": "julius.milan@pantheon.tech",
|
||||
"docker": {
|
||||
"adapters": 5,
|
||||
"image": "ghcr.io/pantheontech/stonework",
|
||||
"start_command": "/root/stonework-gns3-startup.sh",
|
||||
"environment": "INITIAL_LOGLVL=debug,\nMICROSERVICE_LABEL=stonework,\nETCD_CONFIG=,\nCNF_MGMT_SUBNET=127.0.0.1/8"
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,12 @@
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Credentials: SSH ---> username: root ---> password: 1234 MySQL DB: ---> username: root --> password: tacacs Web interface: ---> username: tacgui ---> password: abc123",
|
||||
"usage": "Credentials:\nSSH ---> username: root ---> password: 1234\nMySQL DB: ---> username: root --> password: tacacs\nWeb interface: ---> username: tacgui ---> password: abc123\n\nDefault for 0.9.82 or above:\nIP Address: 10.0.0.254\nNetmask: 255.0.0.0\nGateway: 10.0.0.1",
|
||||
"port_name_format": "Port{port1}",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 1,
|
||||
"ram": 1024,
|
||||
"ram": 4096,
|
||||
"hda_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
@@ -24,6 +24,13 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "tacgui-0.9.82-20201008.qcow2",
|
||||
"version": "0.9.82",
|
||||
"md5sum": "dc0c84aa61d8960a23bf3b309a826f3f",
|
||||
"filesize": 2914844672,
|
||||
"download_url": "https://drive.google.com/open?id=1tlDSyoD5dAWgJu6I76CgYV7BkwhScWSS"
|
||||
},
|
||||
{
|
||||
"filename": "tac_plus.qcow2",
|
||||
"version": "201710201114",
|
||||
@@ -33,6 +40,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "0.9.82",
|
||||
"images": {
|
||||
"hda_disk_image": "tacgui-0.9.82-20201008.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "201710201114",
|
||||
"images": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Tiny Core Linux",
|
||||
"category": "guest",
|
||||
"description": "Core Linux is a smaller variant of Tiny Core without a graphical desktop.\n\nIt's provide a complete Linux system in few MB.",
|
||||
"description": "Core Linux is a smaller variant of Tiny Core without a graphical desktop.\n\nIt provides a complete Linux system using only a few MiB.",
|
||||
"vendor_name": "Team Tiny Core",
|
||||
"vendor_url": "http://distro.ibiblio.org/tinycorelinux",
|
||||
"documentation_url": "http://wiki.tinycorelinux.net/",
|
||||
|
||||
@@ -25,6 +25,13 @@
|
||||
"options": "-nographic"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ubuntu-20.04-server-cloudimg-amd64.img",
|
||||
"version": "20.04 (LTS)",
|
||||
"md5sum": "044bc979b2238192ee3edb44e2bb6405",
|
||||
"filesize": 552337408,
|
||||
"download_url": "https://cloud-images.ubuntu.com/releases/focal/release-20210119.1/ubuntu-20.04-server-cloudimg-amd64.img"
|
||||
},
|
||||
{
|
||||
"filename": "ubuntu-18.04-server-cloudimg-amd64.img",
|
||||
"version": "18.04 (LTS)",
|
||||
@@ -62,6 +69,13 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "20.04 (LTS)",
|
||||
"images": {
|
||||
"hda_disk_image": "ubuntu-20.04-server-cloudimg-amd64.img",
|
||||
"cdrom_image": "ubuntu-cloud-init-data.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "18.04 (LTS)",
|
||||
"images": {
|
||||
|
||||
@@ -25,6 +25,27 @@
|
||||
"options": "-vga virtio"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "Ubuntu 20.10 (64bit).vmdk",
|
||||
"version": "20.10",
|
||||
"md5sum": "d7fb9d7b5f6e55349204d493d00507d2",
|
||||
"filesize": 7512915968,
|
||||
"download_url": "http://www.osboxes.org/ubuntu/"
|
||||
},
|
||||
{
|
||||
"filename": "Ubuntu 20.04.2 (64bit).vmdk",
|
||||
"version": "20.04.2",
|
||||
"md5sum": "e995e5768c1dbee94bc02072d841bb50",
|
||||
"filesize": 7625179136,
|
||||
"download_url": "http://www.osboxes.org/ubuntu/"
|
||||
},
|
||||
{
|
||||
"filename": "Ubuntu 20.04 (64bit).vmdk",
|
||||
"version": "20.04",
|
||||
"md5sum": "cf619dfe9bb8d89e2b18b067f02e57a0",
|
||||
"filesize": 6629883904,
|
||||
"download_url": "http://www.osboxes.org/ubuntu/"
|
||||
},
|
||||
{
|
||||
"filename": "Ubuntu 19.04 (64bit).vmdk",
|
||||
"version": "19.04",
|
||||
@@ -55,6 +76,24 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "20.10",
|
||||
"images": {
|
||||
"hda_disk_image": "Ubuntu 20.10 (64bit).vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "20.04.2",
|
||||
"images": {
|
||||
"hda_disk_image": "Ubuntu 20.04.2 (64bit).vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "20.04",
|
||||
"images": {
|
||||
"hda_disk_image": "Ubuntu 20.04 (64bit).vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "19.04",
|
||||
"images": {
|
||||
|
||||
@@ -1,76 +1,59 @@
|
||||
{
|
||||
"name": "VyOS",
|
||||
"category": "router",
|
||||
"description": "VyOS is a community fork of Vyatta, a Linux-based network operating system that provides software-based network routing, firewall, and VPN functionality. VyOS has a subscription LTS version and a community rolling release. The latest version in this appliance is in the rolling release track.",
|
||||
"description": "VyOS is a community fork of Vyatta, a Linux-based network operating system that provides software-based network routing, firewall, and VPN functionality. VyOS has a subscription LTS version and a community rolling release. The latest version in this appliance is the monthly snapshot of the rolling release track.",
|
||||
"vendor_name": "Linux",
|
||||
"vendor_url": "http://vyos.net/",
|
||||
"documentation_url": "http://vyos.net/wiki/User_Guide",
|
||||
"vendor_url": "https://vyos.net/",
|
||||
"documentation_url": "https://docs.vyos.io/",
|
||||
"product_name": "VyOS",
|
||||
"product_url": "http://vyos.net/",
|
||||
"product_url": "https://vyos.net/",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Default username/password is vyos/vyos. At first boot the router will start from the cdrom, login and then type install system and follow the instructions.",
|
||||
"symbol": "vyos.png",
|
||||
"usage": "Default username/password is vyos/vyos.\n\nAt first boot the router will start from the cdrom. Login and then type \"install image\" and follow the instructions.",
|
||||
"symbol": "vyos.svg",
|
||||
"port_name_format": "eth{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 3,
|
||||
"ram": 512,
|
||||
"hda_disk_interface": "ide",
|
||||
"hda_disk_interface": "scsi",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "dc",
|
||||
"boot_priority": "cd",
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "vyos-1.2.6-amd64.iso",
|
||||
"version": "1.2.6",
|
||||
"md5sum": "dbf5335c16967cd5f768d1ca927666db",
|
||||
"filesize": 428867584,
|
||||
"download_url": "https://downloads.vyos.io/?dir=release/current/1.2.6"
|
||||
"filename": "vyos-1.3.0-epa1-amd64.iso",
|
||||
"version": "1.3.0-epa1",
|
||||
"md5sum": "a2aaa5bd3bc5827909d07a18a9de80a7",
|
||||
"filesize": 331350016,
|
||||
"download_url": "https://vyos.net/get/snapshots/",
|
||||
"direct_download_url": "https://s3.amazonaws.com/s3-us.vyos.io/snapshot/vyos-1.3.0-epa1/generic-iso/vyos-1.3.0-epa1-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "vyos-1.3-rolling-202005040117-amd64.iso",
|
||||
"version": "1.3-rolling-202005040117",
|
||||
"md5sum": "0500d5138cd05239b50f93fb24ac8b55",
|
||||
"filesize": 438304768,
|
||||
"download_url": "https://downloads.vyos.io/?dir=rolling/current/amd64",
|
||||
"direct_download_url": "https://downloads.vyos.io/rolling/current/amd64/vyos-1.3-rolling-202005040117-amd64.iso"
|
||||
"filename": "vyos-1.2.8-amd64.iso",
|
||||
"version": "1.2.8",
|
||||
"md5sum": "0ad879db903efdbf1c39dc945e165931",
|
||||
"filesize": 429916160,
|
||||
"download_url": "https://support.vyos.io/en/downloads/files/vyos-1-2-8-generic-iso-image"
|
||||
},
|
||||
{
|
||||
"filename": "vyos-1.2.7-amd64.iso",
|
||||
"version": "1.2.7",
|
||||
"md5sum": "1a06255edfac63fa3ea89353317130bf",
|
||||
"filesize": 428867584,
|
||||
"download_url": "https://support.vyos.io/en/downloads/files/vyos-1-2-7-generic-iso-image"
|
||||
},
|
||||
{
|
||||
"filename": "vyos-1.1.8-amd64.iso",
|
||||
"version": "1.1.8",
|
||||
"md5sum": "95a141d4b592b81c803cdf7e9b11d8ea",
|
||||
"filesize": 241172480,
|
||||
"download_url": "https://downloads.vyos.io/?dir=release/legacy/1.1.8",
|
||||
"direct_download_url": "https://downloads.vyos.io/release/legacy/1.1.8/vyos-1.1.8-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "vyos-1.1.7-amd64.iso",
|
||||
"version": "1.1.7",
|
||||
"md5sum": "9a7f745a0b0db0d4f1d9eee2a437fb54",
|
||||
"filesize": 245366784,
|
||||
"download_url": "https://downloads.vyos.io/?dir=release/legacy/1.1.7/",
|
||||
"direct_download_url": "https://downloads.vyos.io/release/legacy/1.1.7/vyos-1.1.7-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "vyos-1.1.6-amd64.iso",
|
||||
"version": "1.1.6",
|
||||
"md5sum": "3128954d026e567402a924c2424ce2bf",
|
||||
"filesize": 245366784,
|
||||
"download_url": "hhttps://downloads.vyos.io/?dir=release/legacy/1.1.6/",
|
||||
"direct_download_url": "https://downloads.vyos.io/release/legacy/1.1.6/vyos-1.1.6-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "vyos-1.1.5-amd64.iso",
|
||||
"version": "1.1.5",
|
||||
"md5sum": "193179532011ceaa87ee725bd8f22022",
|
||||
"filesize": 247463936,
|
||||
"download_url": "https://downloads.vyos.io/?dir=release/legacy/1.1.5/",
|
||||
"direct_download_url": "https://downloads.vyos.io/release/legacy/1.1.5/vyos-1.1.5-amd64.iso"
|
||||
"download_url": "https://support.vyos.io/en/downloads/files/vyos-1-1-8-iso",
|
||||
"direct_download_url": "https://s3.amazonaws.com/s3-us.vyos.io/vyos-1.1.8-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "empty8G.qcow2",
|
||||
@@ -83,17 +66,24 @@
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "1.2.6",
|
||||
"name": "1.3.0-epa1",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "vyos-1.2.6-amd64.iso"
|
||||
"cdrom_image": "vyos-1.3.0-epa1-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "1.3-rolling-202005040117",
|
||||
"name": "1.2.8",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "vyos-1.3-rolling-202005040117-amd64.iso"
|
||||
"cdrom_image": "vyos-1.2.8-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "1.2.7",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "vyos-1.2.7-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -102,27 +92,6 @@
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "vyos-1.1.8-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "1.1.7",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "vyos-1.1.7-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "1.1.6",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "vyos-1.1.6-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "1.1.5",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "vyos-1.1.5-amd64.iso"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "Windows",
|
||||
"category": "guest",
|
||||
"description": "Microsoft Windows XP is a graphical operating system developed, marketed, and sold by Microsoft.\n\nMicrosoft has released time limited VMs for testing Internet Explorer.",
|
||||
"vendor_name": "Microsoft",
|
||||
"vendor_url": "http://www.microsoft.com",
|
||||
"product_name": "Windows XP",
|
||||
"registry_version": 3,
|
||||
"status": "experimental",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"qemu": {
|
||||
"adapter_type": "pcnet",
|
||||
"adapters": 2,
|
||||
"ram": 512,
|
||||
"arch": "i386",
|
||||
"console_type": "vnc",
|
||||
"kvm": "require",
|
||||
"options": "-vga std -soundhw es1370 -usbdevice tablet"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "IE8 - WinXP-disk1.vmdk",
|
||||
"version": "XP+IE8",
|
||||
"md5sum": "9cf6a0d5af11bdad26a59731f6494666",
|
||||
"filesize": 1241311744,
|
||||
"download_url": "https://ia802808.us.archive.org/22/items/ie8.winxp.vmware/IE8-WinXP-VMWare.zip"
|
||||
},
|
||||
{
|
||||
"filename": "IE6 - WinXP-disk1.vmdk",
|
||||
"version": "XP+IE6",
|
||||
"md5sum": "f7fc1948749f0a62c3cccf0775d74f05",
|
||||
"filesize": 1063498240,
|
||||
"download_url": "https://ia802903.us.archive.org/25/items/ie6.winxp.vmware/IE6%20-%20WinXP-VMWare.zip"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "XP+IE8",
|
||||
"images": {
|
||||
"hda_disk_image": "IE8 - WinXP-disk1.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "XP+IE6",
|
||||
"images": {
|
||||
"hda_disk_image": "IE6 - WinXP-disk1.vmdk"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -481,7 +481,7 @@ class BaseManager:
|
||||
|
||||
if not path:
|
||||
return ""
|
||||
orig_path = path
|
||||
orig_path = os.path.normpath(path)
|
||||
|
||||
server_config = self.config.get_section_config("Server")
|
||||
img_directory = self.get_images_directory()
|
||||
@@ -494,7 +494,8 @@ class BaseManager:
|
||||
if re.match(r"^[A-Z]:", path) is not None:
|
||||
raise NodeError("{} is not allowed on this remote server. Please only use a file from '{}'".format(path, img_directory))
|
||||
|
||||
if not os.path.isabs(path):
|
||||
if not os.path.isabs(orig_path):
|
||||
|
||||
for directory in valid_directory_prefices:
|
||||
log.debug("Searching for image '{}' in '{}'".format(orig_path, directory))
|
||||
path = self._recursive_search_file_in_directory(directory, orig_path)
|
||||
@@ -503,6 +504,12 @@ class BaseManager:
|
||||
|
||||
# Not found we try the default directory
|
||||
log.debug("Searching for image '{}' in default directory".format(orig_path))
|
||||
|
||||
# check that the image path is in the default image directory
|
||||
#common_prefix = os.path.commonprefix([orig_path, img_directory])
|
||||
#if common_prefix != img_directory:
|
||||
# raise NodeError("{} is not allowed. Please only use a file from '{}'".format(orig_path, img_directory))
|
||||
|
||||
s = os.path.split(orig_path)
|
||||
path = force_unix_path(os.path.join(img_directory, *s))
|
||||
if os.path.exists(path):
|
||||
@@ -517,7 +524,6 @@ class BaseManager:
|
||||
return path
|
||||
raise ImageMissingError(orig_path)
|
||||
|
||||
# Check to see if path is an absolute path to a valid directory
|
||||
path = force_unix_path(path)
|
||||
for directory in valid_directory_prefices:
|
||||
log.debug("Searching for image '{}' in '{}'".format(orig_path, directory))
|
||||
@@ -525,7 +531,8 @@ class BaseManager:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
raise ImageMissingError(orig_path)
|
||||
raise NodeError("{} is not allowed on this remote server. Please only use a file from '{}'".format(path, img_directory))
|
||||
raise NodeError("{} is not allowed on this remote server. Please only use a file from '{}'"
|
||||
.format(path, img_directory))
|
||||
|
||||
def _recursive_search_file_in_directory(self, directory, searched_file):
|
||||
"""
|
||||
@@ -533,12 +540,11 @@ class BaseManager:
|
||||
|
||||
:returns: Path or None if not found
|
||||
"""
|
||||
s = os.path.split(searched_file)
|
||||
|
||||
s = os.path.split(searched_file)
|
||||
for root, dirs, files in os.walk(directory):
|
||||
for file in files:
|
||||
# If filename is the same
|
||||
if s[1] == file and (s[0] == '' or s[0] == os.path.basename(root)):
|
||||
if s[1] == file and (s[0] == '' or root == os.path.join(directory, s[0])):
|
||||
path = os.path.normpath(os.path.join(root, s[1]))
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
@@ -83,8 +83,13 @@ class BaseNode:
|
||||
|
||||
if self._console is not None:
|
||||
if console_type == "vnc":
|
||||
# VNC is a special case and the range must be 5900-6000
|
||||
self._console = self._manager.port_manager.reserve_tcp_port(self._console, self._project, port_range_start=5900, port_range_end=6000)
|
||||
vnc_console_start_port_range, vnc_console_end_port_range = self._get_vnc_console_port_range()
|
||||
self._console = self._manager.port_manager.reserve_tcp_port(
|
||||
self._console,
|
||||
self._project,
|
||||
port_range_start=vnc_console_start_port_range,
|
||||
port_range_end=vnc_console_end_port_range,
|
||||
)
|
||||
elif console_type == "none":
|
||||
self._console = None
|
||||
else:
|
||||
@@ -96,8 +101,11 @@ class BaseNode:
|
||||
|
||||
if self._console is None:
|
||||
if console_type == "vnc":
|
||||
# VNC is a special case and the range must be 5900-6000
|
||||
self._console = self._manager.port_manager.get_free_tcp_port(self._project, port_range_start=5900, port_range_end=6000)
|
||||
vnc_console_start_port_range, vnc_console_end_port_range = self._get_vnc_console_port_range()
|
||||
self._console = self._manager.port_manager.get_free_tcp_port(
|
||||
self._project,
|
||||
port_range_start=vnc_console_start_port_range,
|
||||
port_range_end=vnc_console_end_port_range)
|
||||
elif console_type != "none":
|
||||
self._console = self._manager.port_manager.get_free_tcp_port(self._project)
|
||||
|
||||
@@ -338,6 +346,25 @@ class BaseNode:
|
||||
self._closed = True
|
||||
return True
|
||||
|
||||
def _get_vnc_console_port_range(self):
|
||||
"""
|
||||
Returns the VNC console port range.
|
||||
"""
|
||||
|
||||
server_config = self._manager.config.get_section_config("Server")
|
||||
vnc_console_start_port_range = server_config.getint("vnc_console_start_port_range", 5900)
|
||||
vnc_console_end_port_range = server_config.getint("vnc_console_end_port_range", 10000)
|
||||
|
||||
if not 5900 <= vnc_console_start_port_range <= 65535:
|
||||
raise NodeError("The VNC console start port range must be between 5900 and 65535")
|
||||
if not 5900 <= vnc_console_end_port_range <= 65535:
|
||||
raise NodeError("The VNC console start port range must be between 5900 and 65535")
|
||||
if vnc_console_start_port_range >= vnc_console_end_port_range:
|
||||
raise NodeError(f"The VNC console start port range value ({vnc_console_start_port_range}) "
|
||||
f"cannot be above or equal to the end value ({vnc_console_end_port_range})")
|
||||
|
||||
return vnc_console_start_port_range, vnc_console_end_port_range
|
||||
|
||||
async def start_wrap_console(self):
|
||||
"""
|
||||
Start a telnet proxy for the console allowing multiple telnet clients
|
||||
@@ -403,7 +430,7 @@ class BaseNode:
|
||||
telnet_writer.write(msg.data.encode())
|
||||
await telnet_writer.drain()
|
||||
elif msg.type == aiohttp.WSMsgType.BINARY:
|
||||
await telnet_writer.write(msg.data)
|
||||
telnet_writer.write(msg.data)
|
||||
await telnet_writer.drain()
|
||||
elif msg.type == aiohttp.WSMsgType.ERROR:
|
||||
log.debug("Websocket connection closed with exception {}".format(ws.exception()))
|
||||
@@ -502,7 +529,13 @@ class BaseNode:
|
||||
self._console = None
|
||||
if console is not None:
|
||||
if self.console_type == "vnc":
|
||||
self._console = self._manager.port_manager.reserve_tcp_port(console, self._project, port_range_start=5900, port_range_end=6000)
|
||||
vnc_console_start_port_range, vnc_console_end_port_range = self._get_vnc_console_port_range()
|
||||
self._console = self._manager.port_manager.reserve_tcp_port(
|
||||
console,
|
||||
self._project,
|
||||
port_range_start=vnc_console_start_port_range,
|
||||
port_range_end=vnc_console_end_port_range
|
||||
)
|
||||
else:
|
||||
self._console = self._manager.port_manager.reserve_tcp_port(console, self._project)
|
||||
|
||||
@@ -811,7 +844,7 @@ class BaseNode:
|
||||
"""
|
||||
|
||||
available_ram = int(psutil.virtual_memory().available / (1024 * 1024))
|
||||
percentage_left = psutil.virtual_memory().percent
|
||||
percentage_left = 100 - psutil.virtual_memory().percent
|
||||
if requested_ram > available_ram:
|
||||
message = '"{}" requires {}MB of RAM to run but there is only {}MB - {}% of RAM left on "{}"'.format(self.name,
|
||||
requested_ram,
|
||||
|
||||
@@ -362,12 +362,12 @@ class Cloud(BaseNode):
|
||||
"""
|
||||
|
||||
# Wireless adapters are not well supported by the libpcap on OSX
|
||||
if (await self._is_wifi_adapter_osx(port_info["interface"])):
|
||||
if await self._is_wifi_adapter_osx(port_info["interface"]):
|
||||
raise NodeError("Connecting to a Wireless adapter is not supported on Mac OS")
|
||||
if port_info["interface"].startswith("vmnet"):
|
||||
# Use a special NIO to connect to VMware vmnet interfaces on OSX (libpcap doesn't support them)
|
||||
await self._ubridge_send('bridge add_nio_fusion_vmnet {name} "{interface}"'.format(name=bridge_name,
|
||||
interface=port_info["interface"]))
|
||||
interface=port_info["interface"]))
|
||||
return
|
||||
if not gns3server.utils.interfaces.has_netmask(port_info["interface"]):
|
||||
raise NodeError("Interface {} has no netmask, interface down?".format(port_info["interface"]))
|
||||
@@ -402,6 +402,7 @@ class Cloud(BaseNode):
|
||||
await self._add_ubridge_connection(nio, port_number)
|
||||
self._nios[port_number] = nio
|
||||
except (NodeError, UbridgeError) as e:
|
||||
log.error('Cannot add NIO on cloud "{name}": {error}'.format(name=self._name, error=e))
|
||||
await self._stop_ubridge()
|
||||
self.status = "stopped"
|
||||
self._nios[port_number] = nio
|
||||
|
||||
@@ -35,13 +35,22 @@ class Nat(Cloud):
|
||||
|
||||
def __init__(self, name, node_id, project, manager, ports=None):
|
||||
|
||||
allowed_interfaces = Config.instance().get_section_config("Server").get("allowed_interfaces", None)
|
||||
if allowed_interfaces:
|
||||
allowed_interfaces = allowed_interfaces.split(',')
|
||||
if sys.platform.startswith("linux"):
|
||||
nat_interface = Config.instance().get_section_config("Server").get("default_nat_interface", "virbr0")
|
||||
if allowed_interfaces and nat_interface not in allowed_interfaces:
|
||||
raise NodeError("NAT interface {} is not allowed be used on this server. "
|
||||
"Please check the server configuration file.".format(nat_interface))
|
||||
if nat_interface not in [interface["name"] for interface in gns3server.utils.interfaces.interfaces()]:
|
||||
raise NodeError("NAT interface {} is missing, please install libvirt".format(nat_interface))
|
||||
interface = nat_interface
|
||||
else:
|
||||
nat_interface = Config.instance().get_section_config("Server").get("default_nat_interface", "vmnet8")
|
||||
if allowed_interfaces and nat_interface not in allowed_interfaces:
|
||||
raise NodeError("NAT interface {} is not allowed be used on this server. "
|
||||
"Please check the server configuration file.".format(nat_interface))
|
||||
interfaces = list(filter(lambda x: nat_interface in x.lower(),
|
||||
[interface["name"] for interface in gns3server.utils.interfaces.interfaces()]))
|
||||
if not len(interfaces):
|
||||
|
||||
@@ -79,7 +79,7 @@ class EthernetSwitch(Device):
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
"""
|
||||
|
||||
def __init__(self, name, node_id, project, manager, console=None, console_type="none", ports=None, hypervisor=None):
|
||||
def __init__(self, name, node_id, project, manager, console=None, console_type=None, ports=None, hypervisor=None):
|
||||
|
||||
super().__init__(name, node_id, project, manager, hypervisor)
|
||||
self._nios = {}
|
||||
@@ -90,6 +90,9 @@ class EthernetSwitch(Device):
|
||||
self._console = console
|
||||
self._console_type = console_type
|
||||
|
||||
if self._console_type is None:
|
||||
self._console_type = "none"
|
||||
|
||||
if self._console is not None:
|
||||
self._console = self._manager.port_manager.reserve_tcp_port(self._console, self._project)
|
||||
else:
|
||||
@@ -115,6 +118,7 @@ class EthernetSwitch(Device):
|
||||
"project_id": self.project.id,
|
||||
"ports_mapping": self._ports,
|
||||
"status": "started"}
|
||||
|
||||
return ethernet_switch_info
|
||||
|
||||
@property
|
||||
|
||||
@@ -1182,13 +1182,17 @@ class Router(BaseNode):
|
||||
if not adapter.wic_slot_available(wic_slot_number):
|
||||
raise DynamipsError("WIC slot {wic_slot_number} is already occupied by another WIC".format(wic_slot_number=wic_slot_number))
|
||||
|
||||
if await self.is_running():
|
||||
raise DynamipsError('WIC "{wic}" cannot be added while router "{name}" is running'.format(wic=wic,
|
||||
name=self._name))
|
||||
|
||||
# Dynamips WICs slot IDs start on a multiple of 16
|
||||
# WIC1 = 16, WIC2 = 32 and WIC3 = 48
|
||||
internal_wic_slot_number = 16 * (wic_slot_number + 1)
|
||||
await self._hypervisor.send('vm slot_add_binding "{name}" {slot_number} {wic_slot_number} {wic}'.format(name=self._name,
|
||||
slot_number=slot_number,
|
||||
wic_slot_number=internal_wic_slot_number,
|
||||
wic=wic))
|
||||
slot_number=slot_number,
|
||||
wic_slot_number=internal_wic_slot_number,
|
||||
wic=wic))
|
||||
|
||||
log.info('Router "{name}" [{id}]: {wic} inserted into WIC slot {wic_slot_number}'.format(name=self._name,
|
||||
id=self._id,
|
||||
@@ -1217,12 +1221,16 @@ class Router(BaseNode):
|
||||
if adapter.wic_slot_available(wic_slot_number):
|
||||
raise DynamipsError("No WIC is installed in WIC slot {wic_slot_number}".format(wic_slot_number=wic_slot_number))
|
||||
|
||||
if await self.is_running():
|
||||
raise DynamipsError('WIC cannot be removed from slot {wic_slot_number} while router "{name}" is running'.format(wic_slot_number=wic_slot_number,
|
||||
name=self._name))
|
||||
|
||||
# Dynamips WICs slot IDs start on a multiple of 16
|
||||
# WIC1 = 16, WIC2 = 32 and WIC3 = 48
|
||||
internal_wic_slot_number = 16 * (wic_slot_number + 1)
|
||||
await self._hypervisor.send('vm slot_remove_binding "{name}" {slot_number} {wic_slot_number}'.format(name=self._name,
|
||||
slot_number=slot_number,
|
||||
wic_slot_number=internal_wic_slot_number))
|
||||
slot_number=slot_number,
|
||||
wic_slot_number=internal_wic_slot_number))
|
||||
|
||||
log.info('Router "{name}" [{id}]: {wic} removed from WIC slot {wic_slot_number}'.format(name=self._name,
|
||||
id=self._id,
|
||||
|
||||
@@ -27,10 +27,13 @@ import re
|
||||
import subprocess
|
||||
|
||||
from ...utils.asyncio import subprocess_check_output
|
||||
from ...utils.get_resource import get_resource
|
||||
from ..base_manager import BaseManager
|
||||
from ..error import NodeError, ImageMissingError
|
||||
from .qemu_error import QemuError
|
||||
from .qemu_vm import QemuVM
|
||||
from .utils.guest_cid import get_next_guest_cid
|
||||
from .utils.ziputils import unpack_zip
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -45,6 +48,8 @@ class Qemu(BaseManager):
|
||||
|
||||
super().__init__()
|
||||
self._guest_cid_lock = asyncio.Lock()
|
||||
self.config_disk = "config.img"
|
||||
self._init_config_disk()
|
||||
|
||||
async def create_node(self, *args, **kwargs):
|
||||
"""
|
||||
@@ -147,8 +152,6 @@ class Qemu(BaseManager):
|
||||
log.debug("Searching for Qemu binaries in '{}'".format(path))
|
||||
try:
|
||||
for f in os.listdir(path):
|
||||
if f.endswith("-spice"):
|
||||
continue
|
||||
if (f.startswith("qemu-system") or f.startswith("qemu-kvm") or f == "qemu" or f == "qemu.exe") and \
|
||||
os.access(os.path.join(path, f), os.X_OK) and \
|
||||
os.path.isfile(os.path.join(path, f)):
|
||||
@@ -343,3 +346,21 @@ class Qemu(BaseManager):
|
||||
log.info("Qemu disk '{}' extended by {} MB".format(path, extend))
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
raise QemuError("Could not update disk image {}:{}".format(path, e))
|
||||
|
||||
def _init_config_disk(self):
|
||||
"""
|
||||
Initialize the default config disk
|
||||
"""
|
||||
|
||||
try:
|
||||
self.get_abs_image_path(self.config_disk)
|
||||
except (NodeError, ImageMissingError):
|
||||
config_disk_zip = get_resource("compute/qemu/resources/{}.zip".format(self.config_disk))
|
||||
if config_disk_zip and os.path.exists(config_disk_zip):
|
||||
directory = self.get_images_directory()
|
||||
try:
|
||||
unpack_zip(config_disk_zip, directory)
|
||||
except OSError as e:
|
||||
log.warning("Config disk creation: {}".format(e))
|
||||
else:
|
||||
log.warning("Config disk: image '{}' missing".format(self.config_disk))
|
||||
@@ -26,6 +26,7 @@ import re
|
||||
import shlex
|
||||
import math
|
||||
import shutil
|
||||
import struct
|
||||
import asyncio
|
||||
import socket
|
||||
import gns3server
|
||||
@@ -37,7 +38,9 @@ from gns3server.utils import parse_version, shlex_quote
|
||||
from gns3server.utils.asyncio import subprocess_check_output, cancellable_wait_run_in_executor
|
||||
from .qemu_error import QemuError
|
||||
from .utils.qcow2 import Qcow2, Qcow2Error
|
||||
from .utils.ziputils import pack_zip, unpack_zip
|
||||
from ..adapters.ethernet_adapter import EthernetAdapter
|
||||
from ..error import NodeError, ImageMissingError
|
||||
from ..nios.nio_udp import NIOUDP
|
||||
from ..nios.nio_tap import NIOTAP
|
||||
from ..base_node import BaseNode
|
||||
@@ -101,10 +104,10 @@ class QemuVM(BaseNode):
|
||||
self._hdb_disk_image = ""
|
||||
self._hdc_disk_image = ""
|
||||
self._hdd_disk_image = ""
|
||||
self._hda_disk_interface = "ide"
|
||||
self._hdb_disk_interface = "ide"
|
||||
self._hdc_disk_interface = "ide"
|
||||
self._hdd_disk_interface = "ide"
|
||||
self._hda_disk_interface = "none"
|
||||
self._hdb_disk_interface = "none"
|
||||
self._hdc_disk_interface = "none"
|
||||
self._hdd_disk_interface = "none"
|
||||
self._cdrom_image = ""
|
||||
self._bios_image = ""
|
||||
self._boot_priority = "c"
|
||||
@@ -119,12 +122,28 @@ class QemuVM(BaseNode):
|
||||
self._kernel_command_line = ""
|
||||
self._legacy_networking = False
|
||||
self._replicate_network_connection_state = True
|
||||
self._create_config_disk = False
|
||||
self._on_close = "power_off"
|
||||
self._cpu_throttling = 0 # means no CPU throttling
|
||||
self._process_priority = "low"
|
||||
|
||||
self.mac_address = "" # this will generate a MAC address
|
||||
self.adapters = 1 # creates 1 adapter by default
|
||||
|
||||
# config disk
|
||||
self.config_disk_name = self.manager.config_disk
|
||||
self.config_disk_image = ""
|
||||
if self.config_disk_name:
|
||||
if not shutil.which("mcopy"):
|
||||
log.warning("Config disk: 'mtools' are not installed.")
|
||||
self.config_disk_name = ""
|
||||
else:
|
||||
try:
|
||||
self.config_disk_image = self.manager.get_abs_image_path(self.config_disk_name)
|
||||
except (NodeError, ImageMissingError):
|
||||
log.warning("Config disk: image '{}' missing".format(self.config_disk_name))
|
||||
self.config_disk_name = ""
|
||||
|
||||
log.info('QEMU VM "{name}" [{id}] has been created'.format(name=self._name, id=self._id))
|
||||
|
||||
@property
|
||||
@@ -596,7 +615,7 @@ class QemuVM(BaseNode):
|
||||
|
||||
if not mac_address:
|
||||
# use the node UUID to generate a random MAC address
|
||||
self._mac_address = "0c:%s:%s:%s:%s:00" % (self.project.id[-4:-2], self.project.id[-2:], self.id[-4:-2], self.id[-2:])
|
||||
self._mac_address = "0c:%s:%s:%s:00:00" % (self.id[2:4], self.id[4:6], self.id[6:8])
|
||||
else:
|
||||
self._mac_address = mac_address
|
||||
|
||||
@@ -652,6 +671,30 @@ class QemuVM(BaseNode):
|
||||
log.info('QEMU VM "{name}" [{id}] has disabled network connection state replication'.format(name=self._name, id=self._id))
|
||||
self._replicate_network_connection_state = replicate_network_connection_state
|
||||
|
||||
@property
|
||||
def create_config_disk(self):
|
||||
"""
|
||||
Returns whether a config disk is automatically created on HDD disk interface (secondary slave)
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
return self._create_config_disk
|
||||
|
||||
@create_config_disk.setter
|
||||
def create_config_disk(self, create_config_disk):
|
||||
"""
|
||||
Sets whether a config disk is automatically created on HDD disk interface (secondary slave)
|
||||
|
||||
:param replicate_network_connection_state: boolean
|
||||
"""
|
||||
|
||||
if create_config_disk:
|
||||
log.info('QEMU VM "{name}" [{id}] has enabled the config disk creation feature'.format(name=self._name, id=self._id))
|
||||
else:
|
||||
log.info('QEMU VM "{name}" [{id}] has disabled the config disk creation feature'.format(name=self._name, id=self._id))
|
||||
self._create_config_disk = create_config_disk
|
||||
|
||||
@property
|
||||
def on_close(self):
|
||||
"""
|
||||
@@ -786,20 +829,26 @@ class QemuVM(BaseNode):
|
||||
id=self._id,
|
||||
options=options))
|
||||
|
||||
if not sys.platform.startswith("linux"):
|
||||
if "-no-kvm" in options:
|
||||
options = options.replace("-no-kvm", "")
|
||||
if "-enable-kvm" in options:
|
||||
# "-no-kvm" and "-no-hax' are deprecated since Qemu v5.2
|
||||
if "-no-kvm" in options:
|
||||
options = options.replace("-no-kvm", "-machine accel=tcg")
|
||||
if "-no-hax" in options:
|
||||
options = options.replace("-no-hax", "-machine accel=tcg")
|
||||
|
||||
if "-enable-kvm" in options:
|
||||
if not sys.platform.startswith("linux"):
|
||||
# KVM can only be enabled on Linux
|
||||
options = options.replace("-enable-kvm", "")
|
||||
else:
|
||||
if "-no-hax" in options:
|
||||
options = options.replace("-no-hax", "")
|
||||
if "-enable-hax" in options:
|
||||
else:
|
||||
options = options.replace("-enable-kvm", "-machine accel=kvm")
|
||||
|
||||
if "-enable-hax" in options:
|
||||
if not sys.platform.startswith("win"):
|
||||
# HAXM is only available on Windows
|
||||
options = options.replace("-enable-hax", "")
|
||||
if "-icount" in options and ("-no-kvm" not in options):
|
||||
# automatically add the -no-kvm option if -icount is detected
|
||||
# to help with the migration of ASA VMs created before version 1.4
|
||||
options = "-no-kvm " + options
|
||||
else:
|
||||
options = options.replace("-enable-hax", "-machine accel=hax")
|
||||
|
||||
self._options = options.strip()
|
||||
|
||||
@property
|
||||
@@ -1115,6 +1164,7 @@ class QemuVM(BaseNode):
|
||||
self._stop_cpulimit()
|
||||
if self.on_close != "save_vm_state":
|
||||
await self._clear_save_vm_stated()
|
||||
await self._export_config()
|
||||
await super().stop()
|
||||
|
||||
async def _open_qemu_monitor_connection_vm(self, timeout=10):
|
||||
@@ -1597,23 +1647,16 @@ class QemuVM(BaseNode):
|
||||
def _get_qemu_img(self):
|
||||
"""
|
||||
Search the qemu-img binary in the same binary of the qemu binary
|
||||
for avoiding version incompatibility.
|
||||
to avoid version incompatibility.
|
||||
|
||||
:returns: qemu-img path or raise an error
|
||||
"""
|
||||
qemu_img_path = ""
|
||||
|
||||
qemu_path_dir = os.path.dirname(self.qemu_path)
|
||||
try:
|
||||
for f in os.listdir(qemu_path_dir):
|
||||
if f.startswith("qemu-img"):
|
||||
qemu_img_path = os.path.join(qemu_path_dir, f)
|
||||
except OSError as e:
|
||||
raise QemuError("Error while looking for qemu-img in {}: {}".format(qemu_path_dir, e))
|
||||
|
||||
if not qemu_img_path:
|
||||
raise QemuError("Could not find qemu-img in {}".format(qemu_path_dir))
|
||||
|
||||
return qemu_img_path
|
||||
qemu_image_path = shutil.which("qemu-img", path=qemu_path_dir)
|
||||
if qemu_image_path:
|
||||
return qemu_image_path
|
||||
raise QemuError("Could not find qemu-img in {}".format(qemu_path_dir))
|
||||
|
||||
async def _qemu_img_exec(self, command):
|
||||
|
||||
@@ -1627,6 +1670,166 @@ class QemuVM(BaseNode):
|
||||
log.info("{} returned with {}".format(self._get_qemu_img(), retcode))
|
||||
return retcode
|
||||
|
||||
async def _find_disk_file_format(self, disk):
|
||||
|
||||
qemu_img_path = self._get_qemu_img()
|
||||
try:
|
||||
output = await subprocess_check_output(qemu_img_path, "info", "--output=json", disk)
|
||||
except subprocess.SubprocessError as e:
|
||||
raise QemuError("Error received while checking Qemu disk format: {}".format(e))
|
||||
if output:
|
||||
try:
|
||||
json_data = json.loads(output)
|
||||
except ValueError as e:
|
||||
raise QemuError("Invalid JSON data returned by qemu-img: {}".format(e))
|
||||
return json_data.get("format")
|
||||
|
||||
async def _create_linked_clone(self, disk_name, disk_image, disk):
|
||||
|
||||
try:
|
||||
qemu_img_path = self._get_qemu_img()
|
||||
backing_file_format = await self._find_disk_file_format(disk_image)
|
||||
if not backing_file_format:
|
||||
raise QemuError("Could not detect format for disk image: {}".format(disk_image))
|
||||
backing_options, base_qcow2 = Qcow2.backing_options(disk_image)
|
||||
if base_qcow2 and base_qcow2.crypt_method:
|
||||
# Workaround for https://gitlab.com/qemu-project/qemu/-/issues/441
|
||||
# (we have to pass -u and the size). Also embed secret name.
|
||||
command = [qemu_img_path, "create", "-b", backing_options,
|
||||
"-F", backing_file_format, "-f", "qcow2", "-u", disk, str(base_qcow2.size)]
|
||||
else:
|
||||
command = [qemu_img_path, "create", "-o", "backing_file={}".format(disk_image),
|
||||
"-F", backing_file_format, "-f", "qcow2", disk]
|
||||
|
||||
retcode = await self._qemu_img_exec(command)
|
||||
if retcode:
|
||||
stdout = self.read_qemu_img_stdout()
|
||||
raise QemuError("Could not create '{}' disk image: qemu-img returned with {}\n{}".format(disk_name,
|
||||
retcode,
|
||||
stdout))
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
stdout = self.read_qemu_img_stdout()
|
||||
raise QemuError("Could not create '{}' disk image: {}\n{}".format(disk_name, e, stdout))
|
||||
|
||||
async def _mcopy(self, image, *args):
|
||||
try:
|
||||
# read offset of first partition from MBR
|
||||
with open(image, "rb") as img_file:
|
||||
mbr = img_file.read(512)
|
||||
part_type, offset, signature = struct.unpack("<450xB3xL52xH", mbr)
|
||||
if signature != 0xAA55:
|
||||
raise OSError("{}: invalid MBR".format(image))
|
||||
if part_type not in (1, 4, 6, 11, 12, 14):
|
||||
raise OSError("{}: invalid partition type {:02X}"
|
||||
.format(image, part_type))
|
||||
part_image = image + "@@{}S".format(offset)
|
||||
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
"mcopy", "-i", part_image, *args,
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
cwd=self.working_dir)
|
||||
(stdout, _) = await process.communicate()
|
||||
retcode = process.returncode
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
raise OSError("mcopy failure: {}".format(e))
|
||||
if retcode != 0:
|
||||
stdout = stdout.decode("utf-8").rstrip()
|
||||
if stdout:
|
||||
raise OSError("mcopy failure: {}".format(stdout))
|
||||
else:
|
||||
raise OSError("mcopy failure: return code {}".format(retcode))
|
||||
|
||||
async def _export_config(self):
|
||||
disk_name = getattr(self, "config_disk_name")
|
||||
if not disk_name:
|
||||
return
|
||||
disk = os.path.join(self.working_dir, disk_name)
|
||||
if not os.path.exists(disk):
|
||||
return
|
||||
config_dir = os.path.join(self.working_dir, "configs")
|
||||
zip_file = os.path.join(self.working_dir, "config.zip")
|
||||
try:
|
||||
os.mkdir(config_dir)
|
||||
await self._mcopy(disk, "-s", "-m", "-n", "--", "::/", config_dir)
|
||||
if os.path.exists(zip_file):
|
||||
os.remove(zip_file)
|
||||
pack_zip(zip_file, config_dir)
|
||||
except OSError as e:
|
||||
log.warning("Can't export config: {}".format(e))
|
||||
self.project.emit("log.warning", {"message": "{}: Can't export config: {}".format(self._name, e)})
|
||||
shutil.rmtree(config_dir, ignore_errors=True)
|
||||
|
||||
async def _import_config(self):
|
||||
disk_name = getattr(self, "config_disk_name")
|
||||
if not disk_name:
|
||||
return
|
||||
disk = os.path.join(self.working_dir, disk_name)
|
||||
zip_file = os.path.join(self.working_dir, "config.zip")
|
||||
startup_config = self.hdd_disk_image
|
||||
if startup_config and startup_config.lower().endswith(".zip") and \
|
||||
not os.path.exists(zip_file) and not os.path.exists(disk):
|
||||
try:
|
||||
shutil.copyfile(startup_config, zip_file)
|
||||
except OSError as e:
|
||||
log.warning("Can't access startup config: {}".format(e))
|
||||
self.project.emit("log.warning", {"message": "{}: Can't access startup config: {}".format(self._name, e)})
|
||||
if not os.path.exists(zip_file):
|
||||
return
|
||||
config_dir = os.path.join(self.working_dir, "configs")
|
||||
disk_tmp = disk + ".tmp"
|
||||
try:
|
||||
os.mkdir(config_dir)
|
||||
shutil.copyfile(getattr(self, "config_disk_image"), disk_tmp)
|
||||
unpack_zip(zip_file, config_dir)
|
||||
config_files = [os.path.join(config_dir, fname)
|
||||
for fname in os.listdir(config_dir)]
|
||||
if config_files:
|
||||
await self._mcopy(disk_tmp, "-s", "-m", "-o", "--", *config_files, "::/")
|
||||
os.replace(disk_tmp, disk)
|
||||
except OSError as e:
|
||||
log.warning("Can't import config: {}".format(e))
|
||||
self.project.emit("log.warning", {"message": "{}: Can't import config: {}".format(self._name, e)})
|
||||
if os.path.exists(disk_tmp):
|
||||
os.remove(disk_tmp)
|
||||
os.remove(zip_file)
|
||||
shutil.rmtree(config_dir, ignore_errors=True)
|
||||
|
||||
async def _disk_interface_options(self, disk, disk_index, interface, format=None):
|
||||
options = []
|
||||
extra_drive_options = ""
|
||||
if format:
|
||||
extra_drive_options += ",format={}".format(format)
|
||||
|
||||
# From Qemu man page: if the filename contains comma, you must double it
|
||||
# (for instance, "file=my,,file" to use file "my,file").
|
||||
disk = disk.replace(",", ",,")
|
||||
|
||||
if interface == "sata":
|
||||
# special case, sata controller doesn't exist in Qemu
|
||||
options.extend(["-device", 'ahci,id=ahci{}'.format(disk_index)])
|
||||
options.extend(["-drive", 'file={},if=none,id=drive{},index={},media=disk{}'.format(disk, disk_index, disk_index, extra_drive_options)])
|
||||
qemu_version = await self.manager.get_qemu_version(self.qemu_path)
|
||||
if qemu_version and parse_version(qemu_version) >= parse_version("4.2.0"):
|
||||
# The ‘ide-drive’ device is deprecated since version 4.2.0
|
||||
# https://qemu.readthedocs.io/en/latest/system/deprecated.html#ide-drive-since-4-2
|
||||
options.extend(["-device", 'ide-hd,drive=drive{},bus=ahci{}.0,id=drive{}'.format(disk_index, disk_index, disk_index)])
|
||||
else:
|
||||
options.extend(["-device", 'ide-drive,drive=drive{},bus=ahci{}.0,id=drive{}'.format(disk_index, disk_index, disk_index)])
|
||||
elif interface == "nvme":
|
||||
options.extend(["-drive", 'file={},if=none,id=drive{},index={},media=disk{}'.format(disk, disk_index, disk_index, extra_drive_options)])
|
||||
options.extend(["-device", 'nvme,drive=drive{},serial={}'.format(disk_index, disk_index)])
|
||||
elif interface == "scsi":
|
||||
options.extend(["-device", 'virtio-scsi-pci,id=scsi{}'.format(disk_index)])
|
||||
options.extend(["-drive", 'file={},if=none,id=drive{},index={},media=disk{}'.format(disk, disk_index, disk_index, extra_drive_options)])
|
||||
options.extend(["-device", 'scsi-hd,drive=drive{}'.format(disk_index)])
|
||||
#elif interface == "sd":
|
||||
# options.extend(["-drive", 'file={},id=drive{},index={}{}'.format(disk, disk_index, disk_index, extra_drive_options)])
|
||||
# options.extend(["-device", 'sd-card,drive=drive{},id=drive{}'.format(disk_index, disk_index, disk_index)])
|
||||
else:
|
||||
options.extend(["-drive", 'file={},if={},index={},media=disk,id=drive{}{}'.format(disk, interface, disk_index, disk_index, extra_drive_options)])
|
||||
return options
|
||||
|
||||
async def _disk_options(self):
|
||||
options = []
|
||||
qemu_img_path = self._get_qemu_img()
|
||||
@@ -1634,14 +1837,21 @@ class QemuVM(BaseNode):
|
||||
drives = ["a", "b", "c", "d"]
|
||||
|
||||
for disk_index, drive in enumerate(drives):
|
||||
disk_image = getattr(self, "_hd{}_disk_image".format(drive))
|
||||
interface = getattr(self, "hd{}_disk_interface".format(drive))
|
||||
# prioritize config disk over harddisk d
|
||||
if drive == 'd' and self._create_config_disk:
|
||||
continue
|
||||
|
||||
disk_image = getattr(self, "_hd{}_disk_image".format(drive))
|
||||
if not disk_image:
|
||||
continue
|
||||
|
||||
disk_name = "hd" + drive
|
||||
interface = getattr(self, "hd{}_disk_interface".format(drive))
|
||||
# fail-safe: use "ide" if there is a disk image and no interface type has been explicitly configured
|
||||
if interface == "none":
|
||||
interface = "ide"
|
||||
setattr(self, "hd{}_disk_interface".format(drive), interface)
|
||||
|
||||
disk_name = "hd" + drive
|
||||
if not os.path.isfile(disk_image) or not os.path.exists(disk_image):
|
||||
if os.path.islink(disk_image):
|
||||
raise QemuError("{} disk image '{}' linked to '{}' is not accessible".format(disk_name, disk_image, os.path.realpath(disk_image)))
|
||||
@@ -1654,13 +1864,14 @@ class QemuVM(BaseNode):
|
||||
if retcode == 3:
|
||||
# image has leaked clusters, but is not corrupted, let's try to fix it
|
||||
log.warning("Qemu image {} has leaked clusters".format(disk_image))
|
||||
if (await self._qemu_img_exec([qemu_img_path, "check", "-r", "leaks", "{}".format(disk_image)])) == 3:
|
||||
if await self._qemu_img_exec([qemu_img_path, "check", "-r", "leaks", "{}".format(disk_image)]) == 3:
|
||||
self.project.emit("log.warning", {"message": "Qemu image '{}' has leaked clusters and could not be fixed".format(disk_image)})
|
||||
elif retcode == 2:
|
||||
# image is corrupted, let's try to fix it
|
||||
log.warning("Qemu image {} is corrupted".format(disk_image))
|
||||
if (await self._qemu_img_exec([qemu_img_path, "check", "-r", "all", "{}".format(disk_image)])) == 2:
|
||||
if await self._qemu_img_exec([qemu_img_path, "check", "-r", "all", "{}".format(disk_image)]) == 2:
|
||||
self.project.emit("log.warning", {"message": "Qemu image '{}' is corrupted and could not be fixed".format(disk_image)})
|
||||
# ignore retcode == 1. One reason is that the image is encrypted and there is no encrypt.key-secret available
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
stdout = self.read_qemu_img_stdout()
|
||||
raise QemuError("Could not check '{}' disk image: {}\n{}".format(disk_name, e, stdout))
|
||||
@@ -1669,45 +1880,44 @@ class QemuVM(BaseNode):
|
||||
disk = os.path.join(self.working_dir, "{}_disk.qcow2".format(disk_name))
|
||||
if not os.path.exists(disk):
|
||||
# create the disk
|
||||
try:
|
||||
command = [qemu_img_path, "create", "-o", "backing_file={}".format(disk_image), "-f", "qcow2", disk]
|
||||
retcode = await self._qemu_img_exec(command)
|
||||
if retcode:
|
||||
stdout = self.read_qemu_img_stdout()
|
||||
raise QemuError("Could not create '{}' disk image: qemu-img returned with {}\n{}".format(disk_name,
|
||||
retcode,
|
||||
stdout))
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
stdout = self.read_qemu_img_stdout()
|
||||
raise QemuError("Could not create '{}' disk image: {}\n{}".format(disk_name, e, stdout))
|
||||
await self._create_linked_clone(disk_name, disk_image, disk)
|
||||
else:
|
||||
# The disk exists we check if the clone works
|
||||
backing_file_format = await self._find_disk_file_format(disk_image)
|
||||
if not backing_file_format:
|
||||
raise QemuError("Could not detect format for disk image: {}".format(disk_image))
|
||||
# Rebase the image. This is in case the base image moved to a different directory,
|
||||
# which will be the case if we imported a portable project. This uses
|
||||
# get_abs_image_path(hdX_disk_image) and ignores the old base path embedded
|
||||
# in the qcow2 file itself.
|
||||
try:
|
||||
qcow2 = Qcow2(disk)
|
||||
await qcow2.rebase(qemu_img_path, disk_image)
|
||||
await qcow2.rebase(qemu_img_path, disk_image, backing_file_format)
|
||||
except (Qcow2Error, OSError) as e:
|
||||
raise QemuError("Could not use qcow2 disk image '{}' for {} {}".format(disk_image, disk_name, e))
|
||||
raise QemuError("Could not use qcow2 disk image '{}' for {}: {}".format(disk_image, disk_name, e))
|
||||
|
||||
else:
|
||||
disk = disk_image
|
||||
|
||||
if interface == "sata":
|
||||
# special case, sata controller doesn't exist in Qemu
|
||||
options.extend(["-device", 'ahci,id=ahci{}'.format(disk_index)])
|
||||
options.extend(["-drive", 'file={},if=none,id=drive{},index={},media=disk'.format(disk, disk_index, disk_index)])
|
||||
options.extend(["-device", 'ide-drive,drive=drive{},bus=ahci{}.0,id=drive{}'.format(disk_index, disk_index, disk_index)])
|
||||
elif interface == "nvme":
|
||||
options.extend(["-drive", 'file={},if=none,id=drive{},index={},media=disk'.format(disk, disk_index, disk_index)])
|
||||
options.extend(["-device", 'nvme,drive=drive{},serial={}'.format(disk_index, disk_index)])
|
||||
elif interface == "scsi":
|
||||
options.extend(["-device", 'virtio-scsi-pci,id=scsi{}'.format(disk_index)])
|
||||
options.extend(["-drive", 'file={},if=none,id=drive{},index={},media=disk'.format(disk, disk_index, disk_index)])
|
||||
options.extend(["-device", 'scsi-hd,drive=drive{}'.format(disk_index)])
|
||||
#elif interface == "sd":
|
||||
# options.extend(["-drive", 'file={},id=drive{},index={}'.format(disk, disk_index, disk_index)])
|
||||
# options.extend(["-device", 'sd-card,drive=drive{},id=drive{}'.format(disk_index, disk_index, disk_index)])
|
||||
else:
|
||||
options.extend(["-drive", 'file={},if={},index={},media=disk,id=drive{}'.format(disk, interface, disk_index, disk_index)])
|
||||
options.extend(await self._disk_interface_options(disk, disk_index, interface))
|
||||
|
||||
# config disk
|
||||
disk_image = getattr(self, "config_disk_image")
|
||||
if disk_image and self._create_config_disk:
|
||||
disk_name = getattr(self, "config_disk_name")
|
||||
disk = os.path.join(self.working_dir, disk_name)
|
||||
if self.hdd_disk_interface == "none":
|
||||
# use the HDA interface type if none has been configured for HDD
|
||||
self.hdd_disk_interface = getattr(self, "hda_disk_interface", "none")
|
||||
await self._import_config()
|
||||
disk_exists = os.path.exists(disk)
|
||||
if not disk_exists:
|
||||
try:
|
||||
shutil.copyfile(disk_image, disk)
|
||||
disk_exists = True
|
||||
except OSError as e:
|
||||
log.warning("Could not create '{}' disk image: {}".format(disk_name, e))
|
||||
if disk_exists:
|
||||
options.extend(await self._disk_interface_options(disk, 3, self.hdd_disk_interface, "raw"))
|
||||
|
||||
return options
|
||||
|
||||
@@ -1718,6 +1928,9 @@ class QemuVM(BaseNode):
|
||||
|
||||
if self.linked_clone:
|
||||
disk_image_path = os.path.join(self.working_dir, "{}_disk.qcow2".format(drive_name))
|
||||
if not os.path.exists(disk_image_path):
|
||||
disk_image = getattr(self, "_{}_disk_image".format(drive_name))
|
||||
await self._create_linked_clone(drive_name, disk_image, disk_image_path)
|
||||
else:
|
||||
disk_image_path = getattr(self, "{}_disk_image".format(drive_name))
|
||||
|
||||
@@ -1737,7 +1950,7 @@ class QemuVM(BaseNode):
|
||||
raise QemuError("cdrom image '{}' is not accessible".format(self._cdrom_image))
|
||||
if self._hdc_disk_image:
|
||||
raise QemuError("You cannot use a disk image on hdc disk and a CDROM image at the same time")
|
||||
options.extend(["-cdrom", self._cdrom_image])
|
||||
options.extend(["-cdrom", self._cdrom_image.replace(",", ",,")])
|
||||
return options
|
||||
|
||||
def _bios_option(self):
|
||||
@@ -1749,7 +1962,7 @@ class QemuVM(BaseNode):
|
||||
raise QemuError("bios image '{}' linked to '{}' is not accessible".format(self._bios_image, os.path.realpath(self._bios_image)))
|
||||
else:
|
||||
raise QemuError("bios image '{}' is not accessible".format(self._bios_image))
|
||||
options.extend(["-bios", self._bios_image])
|
||||
options.extend(["-bios", self._bios_image.replace(",", ",,")])
|
||||
return options
|
||||
|
||||
def _linux_boot_options(self):
|
||||
@@ -1761,14 +1974,14 @@ class QemuVM(BaseNode):
|
||||
raise QemuError("initrd file '{}' linked to '{}' is not accessible".format(self._initrd, os.path.realpath(self._initrd)))
|
||||
else:
|
||||
raise QemuError("initrd file '{}' is not accessible".format(self._initrd))
|
||||
options.extend(["-initrd", self._initrd])
|
||||
options.extend(["-initrd", self._initrd.replace(",", ",,")])
|
||||
if self._kernel_image:
|
||||
if not os.path.isfile(self._kernel_image) or not os.path.exists(self._kernel_image):
|
||||
if os.path.islink(self._kernel_image):
|
||||
raise QemuError("kernel image '{}' linked to '{}' is not accessible".format(self._kernel_image, os.path.realpath(self._kernel_image)))
|
||||
else:
|
||||
raise QemuError("kernel image '{}' is not accessible".format(self._kernel_image))
|
||||
options.extend(["-kernel", self._kernel_image])
|
||||
options.extend(["-kernel", self._kernel_image.replace(",", ",,")])
|
||||
if self._kernel_command_line:
|
||||
options.extend(["-append", self._kernel_command_line])
|
||||
|
||||
@@ -1898,7 +2111,7 @@ class QemuVM(BaseNode):
|
||||
if require_kvm is not None:
|
||||
require_hardware_accel = require_kvm
|
||||
|
||||
if enable_hardware_accel and "-no-kvm" not in options and "-no-hax" not in options:
|
||||
if enable_hardware_accel and "-machine accel=tcg" not in options:
|
||||
# Turn OFF hardware acceleration for non x86 architectures
|
||||
if sys.platform.startswith("win"):
|
||||
supported_binaries = ["qemu-system-x86_64.exe", "qemu-system-x86_64w.exe", "qemu-system-i386.exe", "qemu-system-i386w.exe"]
|
||||
@@ -2008,7 +2221,7 @@ class QemuVM(BaseNode):
|
||||
log.info('QEMU VM "{name}" [{id}] VM saved state detected (snapshot name: {snapshot})'.format(name=self._name,
|
||||
id=self.id,
|
||||
snapshot=snapshot_name))
|
||||
return ["-loadvm", snapshot_name]
|
||||
return ["-loadvm", snapshot_name.replace(",", ",,")]
|
||||
|
||||
except subprocess.SubprocessError as e:
|
||||
raise QemuError("Error while looking for the Qemu VM saved state snapshot: {}".format(e))
|
||||
@@ -2020,16 +2233,18 @@ class QemuVM(BaseNode):
|
||||
(to be passed to subprocess.Popen())
|
||||
"""
|
||||
|
||||
vm_name = self._name.replace(",", ",,")
|
||||
project_path = self.project.path.replace(",", ",,")
|
||||
additional_options = self._options.strip()
|
||||
additional_options = additional_options.replace("%vm-name%", '"' + self._name.replace('"', '\\"') + '"')
|
||||
additional_options = additional_options.replace("%vm-name%", '"' + vm_name.replace('"', '\\"') + '"')
|
||||
additional_options = additional_options.replace("%vm-id%", self._id)
|
||||
additional_options = additional_options.replace("%project-id%", self.project.id)
|
||||
additional_options = additional_options.replace("%project-path%", '"' + self.project.path.replace('"', '\\"') + '"')
|
||||
additional_options = additional_options.replace("%project-path%", '"' + project_path.replace('"', '\\"') + '"')
|
||||
additional_options = additional_options.replace("%guest-cid%", str(self._guest_cid))
|
||||
if self._console_type != "none" and self._console:
|
||||
additional_options = additional_options.replace("%console-port%", str(self._console))
|
||||
command = [self.qemu_path]
|
||||
command.extend(["-name", self._name])
|
||||
command.extend(["-name", vm_name])
|
||||
command.extend(["-m", "{}M".format(self._ram)])
|
||||
command.extend(["-smp", "cpus={},sockets=1".format(self._cpus)])
|
||||
if await self._run_with_hardware_acceleration(self.qemu_path, self._options):
|
||||
|
||||
Binary file not shown.
@@ -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 json
|
||||
import os
|
||||
import asyncio
|
||||
import struct
|
||||
@@ -58,11 +59,12 @@ class Qcow2:
|
||||
# uint64_t snapshots_offset;
|
||||
# } QCowHeader;
|
||||
|
||||
struct_format = ">IIQi"
|
||||
struct_format = ">IIQiiQi"
|
||||
with open(self._path, 'rb') as f:
|
||||
content = f.read(struct.calcsize(struct_format))
|
||||
try:
|
||||
self.magic, self.version, self.backing_file_offset, self.backing_file_size = struct.unpack_from(struct_format, content)
|
||||
(self.magic, self.version, self.backing_file_offset, self.backing_file_size,
|
||||
self.cluster_bits, self.size, self.crypt_method) = struct.unpack_from(struct_format, content)
|
||||
|
||||
except struct.error:
|
||||
raise Qcow2Error("Invalid file header for {}".format(self._path))
|
||||
@@ -87,17 +89,48 @@ class Qcow2:
|
||||
return None
|
||||
return path
|
||||
|
||||
async def rebase(self, qemu_img, base_image):
|
||||
@staticmethod
|
||||
def backing_options(base_image):
|
||||
"""
|
||||
If the base_image is encrypted qcow2, return options for the upper layer
|
||||
which include a secret name (equal to the basename)
|
||||
|
||||
:param base_image: Path to the base file (which may or may not be qcow2)
|
||||
|
||||
:returns: (base image string, Qcow2 object representing base image or None)
|
||||
"""
|
||||
|
||||
try:
|
||||
base_qcow2 = Qcow2(base_image)
|
||||
if base_qcow2.crypt_method:
|
||||
# Embed a secret name so it doesn't have to be passed to qemu -drive ...
|
||||
options = {
|
||||
"encrypt.key-secret": os.path.basename(base_image),
|
||||
"driver": "qcow2",
|
||||
"file": {
|
||||
"driver": "file",
|
||||
"filename": base_image,
|
||||
},
|
||||
}
|
||||
return ("json:"+json.dumps(options, separators=(',', ':')), base_qcow2)
|
||||
else:
|
||||
return (base_image, base_qcow2)
|
||||
except Qcow2Error:
|
||||
return (base_image, None) # non-qcow2 base images are acceptable (e.g. vmdk, raw image)
|
||||
|
||||
async def rebase(self, qemu_img, base_image, backing_file_format):
|
||||
"""
|
||||
Rebase a linked clone in order to use the correct disk
|
||||
|
||||
:param qemu_img: Path to the qemu-img binary
|
||||
:param base_image: Path to the base image
|
||||
:param backing_file_format: File format of the base image
|
||||
"""
|
||||
|
||||
if not os.path.exists(base_image):
|
||||
raise FileNotFoundError(base_image)
|
||||
command = [qemu_img, "rebase", "-u", "-b", base_image, self._path]
|
||||
backing_options, _ = Qcow2.backing_options(base_image)
|
||||
command = [qemu_img, "rebase", "-u", "-b", backing_options, "-F", backing_file_format, self._path]
|
||||
process = await asyncio.create_subprocess_exec(*command)
|
||||
retcode = await process.wait()
|
||||
if retcode != 0:
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2020 GNS3 Technologies Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import time
|
||||
import shutil
|
||||
import zipfile
|
||||
|
||||
def pack_zip(filename, root_dir=None, base_dir=None):
|
||||
"""Create a zip archive"""
|
||||
|
||||
if filename[-4:].lower() == ".zip":
|
||||
filename = filename[:-4]
|
||||
shutil.make_archive(filename, 'zip', root_dir, base_dir)
|
||||
|
||||
def unpack_zip(filename, extract_dir=None):
|
||||
"""Unpack a zip archive"""
|
||||
|
||||
dirs = []
|
||||
if not extract_dir:
|
||||
extract_dir = os.getcwd()
|
||||
|
||||
try:
|
||||
with zipfile.ZipFile(filename, 'r') as zfile:
|
||||
for zinfo in zfile.infolist():
|
||||
fname = os.path.join(extract_dir, zinfo.filename)
|
||||
date_time = time.mktime(zinfo.date_time + (0, 0, -1))
|
||||
zfile.extract(zinfo, extract_dir)
|
||||
|
||||
# update timestamp
|
||||
if zinfo.is_dir():
|
||||
dirs.append((fname, date_time))
|
||||
else:
|
||||
os.utime(fname, (date_time, date_time))
|
||||
# update timestamp of directories
|
||||
for fname, date_time in reversed(dirs):
|
||||
os.utime(fname, (date_time, date_time))
|
||||
except zipfile.BadZipFile:
|
||||
raise shutil.ReadError("%s is not a zip file" % filename)
|
||||
@@ -27,6 +27,7 @@ import asyncio
|
||||
import subprocess
|
||||
import logging
|
||||
import codecs
|
||||
import ipaddress
|
||||
|
||||
from collections import OrderedDict
|
||||
from gns3server.utils.interfaces import interfaces
|
||||
@@ -51,6 +52,7 @@ class VMware(BaseManager):
|
||||
self._vmrun_path = None
|
||||
self._host_type = None
|
||||
self._vmnets = []
|
||||
self._vmnets_info = {}
|
||||
self._vmnet_start_range = 2
|
||||
if sys.platform.startswith("win"):
|
||||
self._vmnet_end_range = 19
|
||||
@@ -273,7 +275,7 @@ class VMware(BaseManager):
|
||||
else:
|
||||
# location on Linux
|
||||
vmware_networking_file = "/etc/vmware/networking"
|
||||
vmnet_interfaces = []
|
||||
vmnet_interfaces = {}
|
||||
try:
|
||||
with open(vmware_networking_file, "r", encoding="utf-8") as f:
|
||||
for line in f.read().splitlines():
|
||||
@@ -281,7 +283,20 @@ class VMware(BaseManager):
|
||||
if match:
|
||||
vmnet = "vmnet{}".format(match.group(1))
|
||||
if vmnet not in ("vmnet0", "vmnet1", "vmnet8"):
|
||||
vmnet_interfaces.append(vmnet)
|
||||
vmnet_interfaces[vmnet] = {}
|
||||
with open(vmware_networking_file, "r", encoding="utf-8") as f:
|
||||
for line in f.read().splitlines():
|
||||
match = re.search(r"VNET_([0-9]+)_HOSTONLY_SUBNET\s+(.*)", line)
|
||||
if match:
|
||||
vmnet = "vmnet{}".format(match.group(1))
|
||||
if vmnet in vmnet_interfaces.keys():
|
||||
vmnet_interfaces[vmnet]["subnet"] = match.group(2)
|
||||
match = re.search(r"VNET_([0-9]+)_HOSTONLY_NETMASK\s+(.*)", line)
|
||||
if match:
|
||||
vmnet = "vmnet{}".format(match.group(1))
|
||||
if vmnet in vmnet_interfaces.keys():
|
||||
vmnet_interfaces[vmnet]["netmask"] = match.group(2)
|
||||
|
||||
except OSError as e:
|
||||
raise VMwareError("Cannot open {}: {}".format(vmware_networking_file, e))
|
||||
return vmnet_interfaces
|
||||
@@ -324,6 +339,25 @@ class VMware(BaseManager):
|
||||
raise VMwareError("No VMnet interface available between vmnet{} and vmnet{}. Go to preferences VMware / Network / Configure to add more interfaces.".format(self._vmnet_start_range, self._vmnet_end_range))
|
||||
return self._vmnets.pop(0)
|
||||
|
||||
def find_bridge_interface(self, vmnet_interface):
|
||||
"""
|
||||
Find the bridge interface that is used for the vmnet interface in VMware.
|
||||
"""
|
||||
|
||||
if vmnet_interface in self._vmnets_info.keys():
|
||||
subnet = self._vmnets_info[vmnet_interface].get("subnet", None)
|
||||
netmask = self._vmnets_info[vmnet_interface].get("netmask", None)
|
||||
if subnet and netmask:
|
||||
for interface in interfaces():
|
||||
try:
|
||||
network = ipaddress.ip_network(f"{subnet}/{netmask}")
|
||||
ip = ipaddress.ip_address(interface["ip_address"])
|
||||
except ValueError:
|
||||
continue
|
||||
if ip in network:
|
||||
return interface["name"]
|
||||
return None
|
||||
|
||||
def refresh_vmnet_list(self, ubridge=True):
|
||||
|
||||
if ubridge:
|
||||
@@ -331,6 +365,8 @@ class VMware(BaseManager):
|
||||
vmnet_interfaces = self._get_vmnet_interfaces_ubridge()
|
||||
else:
|
||||
vmnet_interfaces = self._get_vmnet_interfaces()
|
||||
vmnet_interfaces = list(vmnet_interfaces.keys())
|
||||
self._vmnets_info = vmnet_interfaces.copy()
|
||||
|
||||
# remove vmnets already in use
|
||||
for vmware_vm in self._nodes.values():
|
||||
@@ -734,5 +770,4 @@ class VMware(BaseManager):
|
||||
if __name__ == '__main__':
|
||||
loop = asyncio.get_event_loop()
|
||||
vmware = VMware.instance()
|
||||
print("=> Check version")
|
||||
loop.run_until_complete(asyncio.ensure_future(vmware.check_vmware_version()))
|
||||
@@ -23,9 +23,11 @@ import sys
|
||||
import os
|
||||
import asyncio
|
||||
import tempfile
|
||||
import platform
|
||||
|
||||
from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer
|
||||
from gns3server.utils.asyncio.serial import asyncio_open_serial
|
||||
from gns3server.utils import parse_version
|
||||
from gns3server.utils.asyncio import locking
|
||||
from collections import OrderedDict
|
||||
from .vmware_error import VMwareError
|
||||
@@ -252,8 +254,13 @@ class VMwareVM(BaseNode):
|
||||
if self._get_vmx_setting(connected):
|
||||
del self._vmx_pairs[connected]
|
||||
|
||||
use_ubridge = True
|
||||
# use alternative method to find vmnet interfaces on macOS >= 11.0 (BigSur)
|
||||
# because "bridge" interfaces are used instead and they are only created on the VM starts
|
||||
if sys.platform.startswith("darwin") and parse_version(platform.mac_ver()[0]) >= parse_version("11.0.0"):
|
||||
use_ubridge = False
|
||||
self.manager.refresh_vmnet_list(ubridge=use_ubridge)
|
||||
# then configure VMware network adapters
|
||||
self.manager.refresh_vmnet_list()
|
||||
for adapter_number in range(0, self._adapters):
|
||||
|
||||
custom_adapter = self._get_custom_adapter_settings(adapter_number)
|
||||
@@ -333,8 +340,17 @@ class VMwareVM(BaseNode):
|
||||
vmnet_interface = os.path.basename(self._vmx_pairs[vnet])
|
||||
|
||||
if sys.platform.startswith("darwin"):
|
||||
# special case on OSX, we cannot bind VMnet interfaces using the libpcap
|
||||
await self._ubridge_send('bridge add_nio_fusion_vmnet {name} "{interface}"'.format(name=vnet, interface=vmnet_interface))
|
||||
if parse_version(platform.mac_ver()[0]) >= parse_version("11.0.0"):
|
||||
# a bridge interface (bridge100, bridge101 etc.) is used instead of a vmnet interface
|
||||
# on macOS >= 11.0 (Big Sur)
|
||||
vmnet_interface = self.manager.find_bridge_interface(vmnet_interface)
|
||||
if not vmnet_interface:
|
||||
raise VMwareError(f"Could not find bridge interface linked with {vmnet_interface}")
|
||||
block_host_traffic = self.manager.config.get_section_config("VMware").getboolean("block_host_traffic", False)
|
||||
await self._add_ubridge_ethernet_connection(vnet, vmnet_interface, block_host_traffic)
|
||||
else:
|
||||
# special case on macOS, we cannot bind VMnet interfaces using the libpcap
|
||||
await self._ubridge_send('bridge add_nio_fusion_vmnet {name} "{interface}"'.format(name=vnet, interface=vmnet_interface))
|
||||
else:
|
||||
block_host_traffic = self.manager.config.get_section_config("VMware").getboolean("block_host_traffic", False)
|
||||
await self._add_ubridge_ethernet_connection(vnet, vmnet_interface, block_host_traffic)
|
||||
@@ -426,7 +442,7 @@ class VMwareVM(BaseNode):
|
||||
if self.status == "started":
|
||||
return
|
||||
|
||||
if (await self.is_running()):
|
||||
if await self.is_running():
|
||||
raise VMwareError("The VM is already running in VMware")
|
||||
|
||||
ubridge_path = self.ubridge_path
|
||||
@@ -476,7 +492,7 @@ class VMwareVM(BaseNode):
|
||||
await self._stop_ubridge()
|
||||
|
||||
try:
|
||||
if (await self.is_running()):
|
||||
if await self.is_running():
|
||||
if self.on_close == "save_vm_state":
|
||||
await self._control_vm("suspend")
|
||||
elif self.on_close == "shutdown_signal":
|
||||
@@ -728,7 +744,7 @@ class VMwareVM(BaseNode):
|
||||
# check for the connection type
|
||||
connection_type = "ethernet{}.connectiontype".format(adapter_number)
|
||||
if not self._use_any_adapter and connection_type in self._vmx_pairs and self._vmx_pairs[connection_type] in ("nat", "bridged", "hostonly"):
|
||||
if (await self.is_running()):
|
||||
if await self.is_running():
|
||||
raise VMwareError("Attachment '{attachment}' is configured on network adapter {adapter_number}. "
|
||||
"Please stop VMware VM '{name}' to link to this adapter and allow GNS3 to change the attachment type.".format(attachment=self._vmx_pairs[connection_type],
|
||||
adapter_number=adapter_number,
|
||||
|
||||
@@ -251,7 +251,7 @@ class VPCSVM(BaseNode):
|
||||
log.error("Could not start VPCS {}: {}\n{}".format(self._vpcs_path(), e, vpcs_stdout))
|
||||
raise VPCSError("Could not start VPCS {}: {}\n{}".format(self._vpcs_path(), e, vpcs_stdout))
|
||||
|
||||
def _termination_callback(self, returncode):
|
||||
async def _termination_callback(self, returncode):
|
||||
"""
|
||||
Called when the process has stopped.
|
||||
|
||||
@@ -263,6 +263,8 @@ class VPCSVM(BaseNode):
|
||||
self._started = False
|
||||
self.status = "stopped"
|
||||
self._process = None
|
||||
await self._stop_ubridge()
|
||||
await super().stop()
|
||||
if returncode != 0:
|
||||
self.project.emit("log.error", {"message": "VPCS process has stopped, return code: {}\n{}".format(returncode, self.read_vpcs_stdout())})
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ class Controller:
|
||||
self._notification = Notification(self)
|
||||
self.gns3vm = GNS3VM(self)
|
||||
self.symbols = Symbols()
|
||||
self._ssl_context = None
|
||||
self._appliance_manager = ApplianceManager()
|
||||
self._template_manager = TemplateManager()
|
||||
self._iou_license_settings = {"iourc_content": "",
|
||||
@@ -81,16 +82,23 @@ class Controller:
|
||||
name = "Main server"
|
||||
|
||||
computes = self._load_controller_settings()
|
||||
from gns3server.web.web_server import WebServer
|
||||
self._ssl_context = WebServer.instance(host=host, port=port).ssl_context()
|
||||
protocol = server_config.get("protocol", "http")
|
||||
if self._ssl_context and protocol != "https":
|
||||
log.warning("Protocol changed to 'https' for local compute because SSL is enabled".format(port))
|
||||
protocol = "https"
|
||||
try:
|
||||
self._local_server = await self.add_compute(compute_id="local",
|
||||
name=name,
|
||||
protocol=server_config.get("protocol", "http"),
|
||||
protocol=protocol,
|
||||
host=host,
|
||||
console_host=console_host,
|
||||
port=port,
|
||||
user=server_config.get("user", ""),
|
||||
password=server_config.get("password", ""),
|
||||
force=True)
|
||||
force=True,
|
||||
ssl_context=self._ssl_context)
|
||||
except aiohttp.web.HTTPConflict:
|
||||
log.fatal("Cannot access to the local server, make sure something else is not running on the TCP port {}".format(port))
|
||||
sys.exit(1)
|
||||
@@ -108,6 +116,13 @@ class Controller:
|
||||
await self.load_projects()
|
||||
await self._project_auto_open()
|
||||
|
||||
def ssl_context(self):
|
||||
"""
|
||||
Returns the SSL context for the server.
|
||||
"""
|
||||
|
||||
return self._ssl_context
|
||||
|
||||
def _update_config(self):
|
||||
"""
|
||||
Call this when the server configuration file changes.
|
||||
@@ -138,7 +153,16 @@ class Controller:
|
||||
|
||||
log.info("Controller is reloading")
|
||||
self._load_controller_settings()
|
||||
|
||||
# remove all projects deleted from disk.
|
||||
for project in self._projects.copy().values():
|
||||
if not os.path.exists(project.path) or not os.listdir(project.path):
|
||||
log.info(f"Project '{project.name}' doesn't exist on the disk anymore, closing...")
|
||||
await project.close()
|
||||
self.remove_project(project)
|
||||
|
||||
await self.load_projects()
|
||||
await self._project_auto_open()
|
||||
|
||||
def check_can_write_config(self):
|
||||
"""
|
||||
@@ -266,7 +290,7 @@ class Controller:
|
||||
"""
|
||||
|
||||
server_config = Config.instance().get_section_config("Server")
|
||||
images_path = os.path.expanduser(server_config.get("images_path", "~/GNS3/projects"))
|
||||
images_path = os.path.expanduser(server_config.get("images_path", "~/GNS3/images"))
|
||||
os.makedirs(images_path, exist_ok=True)
|
||||
return images_path
|
||||
|
||||
@@ -276,9 +300,9 @@ class Controller:
|
||||
"""
|
||||
|
||||
server_config = Config.instance().get_section_config("Server")
|
||||
images_path = os.path.expanduser(server_config.get("configs_path", "~/GNS3/projects"))
|
||||
os.makedirs(images_path, exist_ok=True)
|
||||
return images_path
|
||||
configs_path = os.path.expanduser(server_config.get("configs_path", "~/GNS3/configs"))
|
||||
os.makedirs(configs_path, exist_ok=True)
|
||||
return configs_path
|
||||
|
||||
async def add_compute(self, compute_id=None, name=None, force=False, connect=True, **kwargs):
|
||||
"""
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import json
|
||||
import uuid
|
||||
import asyncio
|
||||
@@ -70,7 +71,7 @@ class ApplianceManager:
|
||||
"""
|
||||
|
||||
server_config = Config.instance().get_section_config("Server")
|
||||
appliances_path = os.path.expanduser(server_config.get("appliances_path", "~/GNS3/projects"))
|
||||
appliances_path = os.path.expanduser(server_config.get("appliances_path", "~/GNS3/appliances"))
|
||||
os.makedirs(appliances_path, exist_ok=True)
|
||||
return appliances_path
|
||||
|
||||
@@ -181,6 +182,7 @@ class ApplianceManager:
|
||||
Controller.instance().save()
|
||||
json_data = await response.json()
|
||||
appliances_dir = get_resource('appliances')
|
||||
downloaded_appliance_files = []
|
||||
for appliance in json_data:
|
||||
if appliance["type"] == "file":
|
||||
appliance_name = appliance["name"]
|
||||
@@ -201,6 +203,21 @@ class ApplianceManager:
|
||||
f.write(appliance_data)
|
||||
except OSError as e:
|
||||
raise aiohttp.web.HTTPConflict(text="Could not write appliance file '{}': {}".format(path, e))
|
||||
downloaded_appliance_files.append(appliance_name)
|
||||
|
||||
# delete old appliance files
|
||||
for filename in os.listdir(appliances_dir):
|
||||
file_path = os.path.join(appliances_dir, filename)
|
||||
if filename in downloaded_appliance_files:
|
||||
continue
|
||||
try:
|
||||
if os.path.isfile(file_path) or os.path.islink(file_path):
|
||||
log.info("Deleting old appliance file {}".format(file_path))
|
||||
os.unlink(file_path)
|
||||
except OSError as e:
|
||||
log.warning("Could not delete old appliance file '{}': {}".format(file_path, e))
|
||||
continue
|
||||
|
||||
except ValueError as e:
|
||||
raise aiohttp.web.HTTPConflict(text="Could not read appliances information from GitHub: {}".format(e))
|
||||
|
||||
|
||||
@@ -57,7 +57,8 @@ class Compute:
|
||||
A GNS3 compute.
|
||||
"""
|
||||
|
||||
def __init__(self, compute_id, controller=None, protocol="http", host="localhost", port=3080, user=None, password=None, name=None, console_host=None):
|
||||
def __init__(self, compute_id, controller=None, protocol="http", host="localhost",
|
||||
port=3080, user=None, password=None, name=None, console_host=None, ssl_context=None):
|
||||
self._http_session = None
|
||||
assert controller is not None
|
||||
log.info("Create compute %s", compute_id)
|
||||
@@ -81,6 +82,7 @@ class Compute:
|
||||
self._cpu_usage_percent = None
|
||||
self._memory_usage_percent = None
|
||||
self._last_error = None
|
||||
self._ssl_context = ssl_context
|
||||
self._capabilities = {
|
||||
"version": None,
|
||||
"node_types": []
|
||||
@@ -92,7 +94,9 @@ class Compute:
|
||||
|
||||
def _session(self):
|
||||
if self._http_session is None or self._http_session.closed is True:
|
||||
self._http_session = aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=None, force_close=True))
|
||||
self._http_session = aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=None,
|
||||
force_close=True,
|
||||
ssl_context=self._ssl_context))
|
||||
return self._http_session
|
||||
|
||||
#def __del__(self):
|
||||
@@ -308,7 +312,7 @@ class Compute:
|
||||
url = self._getUrl("/projects/{}/files/{}".format(project.id, path))
|
||||
response = await self._session().request("GET", url, auth=self._auth)
|
||||
if response.status == 404:
|
||||
raise aiohttp.web.HTTPNotFound(text="{} not found on compute".format(path))
|
||||
raise aiohttp.web.HTTPNotFound(text="File '{}' not found on compute".format(path))
|
||||
return response
|
||||
|
||||
async def download_image(self, image_type, image):
|
||||
@@ -323,7 +327,7 @@ class Compute:
|
||||
url = self._getUrl("/{}/images/{}".format(image_type, image))
|
||||
response = await self._session().request("GET", url, auth=self._auth)
|
||||
if response.status == 404:
|
||||
raise aiohttp.web.HTTPNotFound(text="{} not found on compute".format(image))
|
||||
raise aiohttp.web.HTTPNotFound(text="Image '{}' not found on compute".format(image))
|
||||
return response
|
||||
|
||||
async def http_query(self, method, path, data=None, dont_connect=False, **kwargs):
|
||||
|
||||
@@ -66,22 +66,26 @@ async def export_project(zstream, project, temporary_dir, include_images=False,
|
||||
|
||||
# Export the local files
|
||||
for root, dirs, files in os.walk(project._path, topdown=True, followlinks=False):
|
||||
files = [f for f in files if _is_exportable(os.path.join(root, f), include_snapshots)]
|
||||
for file in files:
|
||||
path = os.path.join(root, file)
|
||||
# check if we can export the file
|
||||
try:
|
||||
open(path).close()
|
||||
except OSError as e:
|
||||
msg = "Could not export file {}: {}".format(path, e)
|
||||
log.warning(msg)
|
||||
project.emit_notification("log.warning", {"message": msg})
|
||||
continue
|
||||
# ignore the .gns3 file
|
||||
if file.endswith(".gns3"):
|
||||
continue
|
||||
_patch_mtime(path)
|
||||
zstream.write(path, os.path.relpath(path, project._path))
|
||||
try:
|
||||
files = [f for f in files if _is_exportable(os.path.join(root, f), include_snapshots)]
|
||||
for file in files:
|
||||
path = os.path.join(root, file)
|
||||
# check if we can export the file
|
||||
try:
|
||||
open(path).close()
|
||||
except OSError as e:
|
||||
msg = "Could not export file {}: {}".format(path, e)
|
||||
log.warning(msg)
|
||||
project.emit_notification("log.warning", {"message": msg})
|
||||
continue
|
||||
# ignore the .gns3 file
|
||||
if file.endswith(".gns3"):
|
||||
continue
|
||||
_patch_mtime(path)
|
||||
zstream.write(path, os.path.relpath(path, project._path))
|
||||
except FileNotFoundError as e:
|
||||
log.warning("Cannot export local file: {}".format(e))
|
||||
continue
|
||||
|
||||
# Export files from remote computes
|
||||
for compute in project.computes:
|
||||
@@ -91,8 +95,9 @@ async def export_project(zstream, project, temporary_dir, include_images=False,
|
||||
if _is_exportable(compute_file["path"], include_snapshots):
|
||||
log.debug("Downloading file '{}' from compute '{}'".format(compute_file["path"], compute.id))
|
||||
response = await compute.download_file(project, compute_file["path"])
|
||||
#if response.status != 200:
|
||||
# raise aiohttp.web.HTTPConflict(text="Cannot export file from compute '{}'. Compute returned status code {}.".format(compute.id, response.status))
|
||||
if response.status != 200:
|
||||
log.warning("Cannot export file from compute '{}'. Compute returned status code {}.".format(compute.id, response.status))
|
||||
continue
|
||||
(fd, temp_path) = tempfile.mkstemp(dir=temporary_dir)
|
||||
async with aiofiles.open(fd, 'wb') as f:
|
||||
while True:
|
||||
|
||||
@@ -49,6 +49,7 @@ class GNS3VM:
|
||||
"headless": False,
|
||||
"enable": False,
|
||||
"engine": "vmware",
|
||||
"allocate_vcpus_ram": True,
|
||||
"ram": 2048,
|
||||
"vcpus": 1,
|
||||
"port": 80,
|
||||
@@ -311,6 +312,7 @@ class GNS3VM:
|
||||
if self._settings["vmname"] is None:
|
||||
return
|
||||
log.info("Start the GNS3 VM")
|
||||
engine.allocate_vcpus_ram = self._settings["allocate_vcpus_ram"]
|
||||
engine.vmname = self._settings["vmname"]
|
||||
engine.ram = self._settings["ram"]
|
||||
engine.vcpus = self._settings["vcpus"]
|
||||
|
||||
@@ -30,6 +30,7 @@ class BaseGNS3VM:
|
||||
self._ip_address = None
|
||||
self._port = 80 # value not used, will be overwritten
|
||||
self._headless = False
|
||||
self._allocate_vcpus_ram = True
|
||||
self._vcpus = 1
|
||||
self._ram = 1024
|
||||
self._user = ""
|
||||
@@ -203,6 +204,26 @@ class BaseGNS3VM:
|
||||
|
||||
self._headless = value
|
||||
|
||||
@property
|
||||
def allocate_vcpus_ram(self):
|
||||
"""
|
||||
Returns whether VCPUs and RAM settings should be configured for the GNS3 VM.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
return self._allocate_vcpus_ram
|
||||
|
||||
@allocate_vcpus_ram.setter
|
||||
def allocate_vcpus_ram(self, value):
|
||||
"""
|
||||
Sets whether VCPUs and RAM settings should be configured for the GNS3 VM.
|
||||
|
||||
:param value: boolean
|
||||
"""
|
||||
|
||||
self._allocate_vcpus_ram = value
|
||||
|
||||
@property
|
||||
def vcpus(self):
|
||||
"""
|
||||
|
||||
@@ -251,9 +251,10 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
raise GNS3VMError("Could not find Hyper-V VM {}".format(self.vmname))
|
||||
|
||||
if not self._is_running():
|
||||
log.info("Update GNS3 VM settings (CPU and RAM)")
|
||||
# set the number of vCPUs and amount of RAM
|
||||
self._set_vcpus_ram(self.vcpus, self.ram)
|
||||
if self.allocate_vcpus_ram:
|
||||
log.info("Update GNS3 VM settings (CPU and RAM)")
|
||||
# set the number of vCPUs and amount of RAM
|
||||
self._set_vcpus_ram(self.vcpus, self.ram)
|
||||
|
||||
# start the VM
|
||||
try:
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
# 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
|
||||
|
||||
from .base_gns3_vm import BaseGNS3VM
|
||||
from .gns3_vm_error import GNS3VMError
|
||||
|
||||
|
||||
@@ -259,9 +259,12 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
log.info('"{}" state is {}'.format(self._vmname, vm_state))
|
||||
|
||||
if vm_state == "poweroff":
|
||||
log.info("Update GNS3 VM settings (CPU, RAM and Hardware Virtualization)")
|
||||
await self.set_vcpus(self.vcpus)
|
||||
await self.set_ram(self.ram)
|
||||
if self.allocate_vcpus_ram:
|
||||
log.info("Update GNS3 VM vCPUs and RAM settings")
|
||||
await self.set_vcpus(self.vcpus)
|
||||
await self.set_ram(self.ram)
|
||||
|
||||
log.info("Update GNS3 VM Hardware Virtualization setting")
|
||||
await self.enable_nested_hw_virt()
|
||||
|
||||
if vm_state in ("poweroff", "saved"):
|
||||
|
||||
@@ -148,9 +148,12 @@ class VMwareGNS3VM(BaseGNS3VM):
|
||||
except VMwareError as e:
|
||||
raise GNS3VMError("Could not list VMware VMs: {}".format(str(e)))
|
||||
if not running:
|
||||
log.info("Update GNS3 VM settings (CPU, RAM and Hardware Virtualization)")
|
||||
# set the number of vCPUs and amount of RAM
|
||||
await self._set_vcpus_ram(self.vcpus, self.ram)
|
||||
if self.allocate_vcpus_ram:
|
||||
log.info("Update GNS3 VM vCPUs and RAM settings")
|
||||
await self._set_vcpus_ram(self.vcpus, self.ram)
|
||||
|
||||
log.info("Update GNS3 VM Hardware Virtualization setting")
|
||||
await self._set_extra_options()
|
||||
|
||||
# start the VM
|
||||
|
||||
@@ -38,7 +38,8 @@ Handle the import of project from a .gns3project
|
||||
"""
|
||||
|
||||
|
||||
async def import_project(controller, project_id, stream, location=None, name=None, keep_compute_id=False):
|
||||
async def import_project(controller, project_id, stream, location=None, name=None, keep_compute_id=False,
|
||||
auto_start=False, auto_open=False, auto_close=True):
|
||||
"""
|
||||
Import a project contain in a zip file
|
||||
|
||||
@@ -98,9 +99,9 @@ async def import_project(controller, project_id, stream, location=None, name=Non
|
||||
topology = load_topology(os.path.join(path, "project.gns3"))
|
||||
topology["name"] = project_name
|
||||
# To avoid unexpected behavior (project start without manual operations just after import)
|
||||
topology["auto_start"] = False
|
||||
topology["auto_open"] = False
|
||||
topology["auto_close"] = True
|
||||
topology["auto_start"] = auto_start
|
||||
topology["auto_open"] = auto_open
|
||||
topology["auto_close"] = auto_close
|
||||
|
||||
# Generate a new node id
|
||||
node_old_to_new = {}
|
||||
|
||||
@@ -124,6 +124,7 @@ class Link:
|
||||
self._link_type = "ethernet"
|
||||
self._suspended = False
|
||||
self._filters = {}
|
||||
self._link_style = {}
|
||||
|
||||
@property
|
||||
def filters(self):
|
||||
@@ -209,6 +210,12 @@ class Link:
|
||||
self._project.emit_notification("link.updated", self.__json__())
|
||||
self._project.dump()
|
||||
|
||||
async def update_link_style(self, link_style):
|
||||
if link_style != self._link_style:
|
||||
self._link_style = link_style
|
||||
self._project.emit_notification("link.updated", self.__json__())
|
||||
self._project.dump()
|
||||
|
||||
@property
|
||||
def created(self):
|
||||
"""
|
||||
@@ -454,6 +461,7 @@ class Link:
|
||||
"nodes": res,
|
||||
"link_id": self._id,
|
||||
"filters": self._filters,
|
||||
"link_style": self._link_style,
|
||||
"suspend": self._suspended
|
||||
}
|
||||
return {
|
||||
@@ -466,5 +474,6 @@ class Link:
|
||||
"capture_compute_id": self.capture_compute_id,
|
||||
"link_type": self._link_type,
|
||||
"filters": self._filters,
|
||||
"link_style": self._link_style,
|
||||
"suspend": self._suspended
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import os
|
||||
from .compute import ComputeConflict, ComputeError
|
||||
from .ports.port_factory import PortFactory, StandardPortFactory, DynamipsPortFactory
|
||||
from ..utils.images import images_directories
|
||||
from ..config import Config
|
||||
from ..utils.qt import qt_font_to_style
|
||||
|
||||
|
||||
@@ -263,10 +264,12 @@ class Node:
|
||||
if val is None:
|
||||
val = ":/symbols/computer.svg"
|
||||
|
||||
# No abs path, fix them (bug of 1.X)
|
||||
try:
|
||||
if not val.startswith(":") and os.path.abspath(val):
|
||||
val = os.path.basename(val)
|
||||
if not val.startswith(":") and os.path.isabs(val):
|
||||
server_config = Config.instance().get_section_config("Server")
|
||||
default_symbol_directory = os.path.expanduser(server_config.get("symbols_path", "~/GNS3/symbols"))
|
||||
if os.path.commonprefix([default_symbol_directory, val]) != default_symbol_directory:
|
||||
val = os.path.basename(val)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
@@ -174,6 +174,7 @@ class Project:
|
||||
self._links = {}
|
||||
self._drawings = {}
|
||||
self._snapshots = {}
|
||||
self._computes = []
|
||||
|
||||
# List the available snapshots
|
||||
snapshot_dir = os.path.join(self.path, "snapshots")
|
||||
@@ -564,6 +565,9 @@ class Project:
|
||||
if node_id in self._nodes:
|
||||
return self._nodes[node_id]
|
||||
|
||||
if compute.id not in self._computes:
|
||||
self._computes.append(compute.id)
|
||||
|
||||
if node_type == "iou":
|
||||
async with self._iou_id_lock:
|
||||
# wait for a IOU node to be completely created before adding a new one
|
||||
@@ -571,10 +575,10 @@ class Project:
|
||||
# to generate MAC addresses) when creating multiple IOU node at the same time
|
||||
if "properties" in kwargs.keys():
|
||||
# allocate a new application id for nodes loaded from the project
|
||||
kwargs.get("properties")["application_id"] = get_next_application_id(self._controller.projects, compute)
|
||||
kwargs.get("properties")["application_id"] = get_next_application_id(self._controller.projects, self._computes)
|
||||
elif "application_id" not in kwargs.keys() and not kwargs.get("properties"):
|
||||
# allocate a new application id for nodes added to the project
|
||||
kwargs["application_id"] = get_next_application_id(self._controller.projects, compute)
|
||||
kwargs["application_id"] = get_next_application_id(self._controller.projects, self._computes)
|
||||
node = await self._create_node(compute, name, node_id, node_type, **kwargs)
|
||||
else:
|
||||
node = await self._create_node(compute, name, node_id, node_type, **kwargs)
|
||||
@@ -604,6 +608,8 @@ class Project:
|
||||
self.remove_allocated_node_name(node.name)
|
||||
del self._nodes[node.id]
|
||||
await node.destroy()
|
||||
# refresh the compute IDs list
|
||||
self._computes = [n.compute.id for n in self.nodes.values()]
|
||||
self.dump()
|
||||
self.emit_notification("node.deleted", node.__json__())
|
||||
|
||||
@@ -931,6 +937,14 @@ class Project:
|
||||
topology = project_data["topology"]
|
||||
for compute in topology.get("computes", []):
|
||||
await self.controller.add_compute(**compute)
|
||||
|
||||
# Get all compute used in the project
|
||||
# used to allocate application IDs for IOU nodes.
|
||||
for node in topology.get("nodes", []):
|
||||
compute_id = node.get("compute_id")
|
||||
if compute_id not in self._computes:
|
||||
self._computes.append(compute_id)
|
||||
|
||||
for node in topology.get("nodes", []):
|
||||
compute = self.controller.get_compute(node.pop("compute_id"))
|
||||
name = node.pop("name")
|
||||
@@ -943,6 +957,8 @@ class Project:
|
||||
link = await self.add_link(link_id=link_data["link_id"])
|
||||
if "filters" in link_data:
|
||||
await link.update_filters(link_data["filters"])
|
||||
if "link_style" in link_data:
|
||||
await link.update_link_style(link_data["link_style"])
|
||||
for node_link in link_data.get("nodes", []):
|
||||
node = self.get_node(node_link["node_id"])
|
||||
port = node.get_port(node_link["adapter_number"], node_link["port_number"])
|
||||
|
||||
@@ -121,7 +121,9 @@ class Snapshot:
|
||||
if os.path.exists(project_files_path):
|
||||
await wait_run_in_executor(shutil.rmtree, project_files_path)
|
||||
with open(self._path, "rb") as f:
|
||||
project = await import_project(self._project.controller, self._project.id, f, location=self._project.path)
|
||||
project = await import_project(self._project.controller, self._project.id, f, location=self._project.path,
|
||||
auto_start=self._project.auto_start, auto_open=self._project.auto_open,
|
||||
auto_close=self._project.auto_close)
|
||||
except (OSError, PermissionError) as e:
|
||||
raise aiohttp.web.HTTPConflict(text=str(e))
|
||||
await project.open()
|
||||
|
||||
@@ -104,8 +104,7 @@ class Symbols:
|
||||
'builtin': False,
|
||||
'theme': "Custom symbols"})
|
||||
self._symbols_path[symbol_file] = os.path.join(root, filename)
|
||||
|
||||
symbols.sort(key=lambda x: x["filename"])
|
||||
symbols.sort(key=lambda x: x["theme"])
|
||||
return symbols
|
||||
|
||||
def symbols_path(self):
|
||||
|
||||
@@ -63,13 +63,13 @@ def _check_topology_schema(topo):
|
||||
error = "Invalid data in topology file: {} in schema: {}".format(
|
||||
e.message,
|
||||
json.dumps(e.schema))
|
||||
log.critical(error)
|
||||
log.debug(error)
|
||||
raise aiohttp.web.HTTPConflict(text=error)
|
||||
|
||||
|
||||
def project_to_topology(project):
|
||||
"""
|
||||
:return: A dictionnary with the topology ready to dump to a .gns3
|
||||
:return: A dictionary with the topology ready to dump to a .gns3
|
||||
"""
|
||||
data = {
|
||||
"project_id": project.id,
|
||||
|
||||
@@ -58,7 +58,7 @@ class CrashReport:
|
||||
Report crash to a third party service
|
||||
"""
|
||||
|
||||
DSN = "https://c0b6ce011d024391831923745a47c33f:459ea5884d3944f092b02e4183cb6d52@o19455.ingest.sentry.io/38482"
|
||||
DSN = "https://959feb527c7441068b1bf80301b6e2c4:efa6d99da4c64faa8a7d929360765b40@o19455.ingest.sentry.io/38482"
|
||||
_instance = None
|
||||
|
||||
def __init__(self):
|
||||
|
||||
@@ -470,7 +470,8 @@ class DynamipsVMHandler:
|
||||
async def upload_image(request, response):
|
||||
|
||||
dynamips_manager = Dynamips.instance()
|
||||
await dynamips_manager.write_image(request.match_info["filename"], request.content)
|
||||
filename = os.path.normpath(request.match_info["filename"])
|
||||
await dynamips_manager.write_image(filename, request.content)
|
||||
response.set_status(204)
|
||||
|
||||
@Route.get(
|
||||
@@ -484,15 +485,15 @@ class DynamipsVMHandler:
|
||||
raw=True,
|
||||
description="Download a Dynamips IOS image")
|
||||
async def download_image(request, response):
|
||||
filename = request.match_info["filename"]
|
||||
|
||||
filename = os.path.normpath(request.match_info["filename"])
|
||||
|
||||
# Raise error if user try to escape
|
||||
if filename[0] == "." or os.path.sep in filename:
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
dynamips_manager = Dynamips.instance()
|
||||
image_path = dynamips_manager.get_abs_image_path(filename)
|
||||
|
||||
# Raise error if user try to escape
|
||||
if filename[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
await response.stream_file(image_path)
|
||||
|
||||
@Route.post(
|
||||
|
||||
@@ -53,12 +53,12 @@ class EthernetSwitchHandler:
|
||||
# Use the Dynamips Ethernet switch to simulate this node
|
||||
dynamips_manager = Dynamips.instance()
|
||||
node = await dynamips_manager.create_node(request.json.pop("name"),
|
||||
request.match_info["project_id"],
|
||||
request.json.get("node_id"),
|
||||
console=request.json.get("console"),
|
||||
console_type=request.json.get("console_type"),
|
||||
node_type="ethernet_switch",
|
||||
ports=request.json.get("ports_mapping"))
|
||||
request.match_info["project_id"],
|
||||
request.json.get("node_id"),
|
||||
console=request.json.get("console"),
|
||||
console_type=request.json.get("console_type"),
|
||||
node_type="ethernet_switch",
|
||||
ports=request.json.get("ports_mapping"))
|
||||
|
||||
# On Linux, use the generic switch
|
||||
# builtin_manager = Builtin.instance()
|
||||
|
||||
@@ -428,7 +428,8 @@ class IOUHandler:
|
||||
async def upload_image(request, response):
|
||||
|
||||
iou_manager = IOU.instance()
|
||||
await iou_manager.write_image(request.match_info["filename"], request.content)
|
||||
filename = os.path.normpath(request.match_info["filename"])
|
||||
await iou_manager.write_image(filename, request.content)
|
||||
response.set_status(204)
|
||||
|
||||
|
||||
@@ -443,15 +444,15 @@ class IOUHandler:
|
||||
raw=True,
|
||||
description="Download an IOU image")
|
||||
async def download_image(request, response):
|
||||
filename = request.match_info["filename"]
|
||||
|
||||
filename = os.path.normpath(request.match_info["filename"])
|
||||
|
||||
# Raise error if user try to escape
|
||||
if filename[0] == "." or os.path.sep in filename:
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
iou_manager = IOU.instance()
|
||||
image_path = iou_manager.get_abs_image_path(filename)
|
||||
|
||||
# Raise error if user try to escape
|
||||
if filename[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
await response.stream_file(image_path)
|
||||
|
||||
@Route.get(
|
||||
|
||||
@@ -20,12 +20,12 @@ import asyncio
|
||||
import json
|
||||
import os
|
||||
import psutil
|
||||
import tempfile
|
||||
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.compute.project_manager import ProjectManager
|
||||
from gns3server.compute import MODULES
|
||||
from gns3server.utils.cpu_percent import CpuPercent
|
||||
from gns3server.utils.path import is_safe_path
|
||||
|
||||
from gns3server.schemas.project import (
|
||||
PROJECT_OBJECT_SCHEMA,
|
||||
@@ -247,14 +247,13 @@ class ProjectHandler:
|
||||
|
||||
pm = ProjectManager.instance()
|
||||
project = pm.get_project(request.match_info["project_id"])
|
||||
path = request.match_info["path"]
|
||||
path = os.path.normpath(path)
|
||||
path = os.path.normpath(request.match_info["path"])
|
||||
|
||||
# Raise error if user try to escape
|
||||
if path[0] == ".":
|
||||
if not is_safe_path(path, project.path):
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
path = os.path.join(project.path, path)
|
||||
|
||||
path = os.path.join(project.path, path)
|
||||
await response.stream_file(path)
|
||||
|
||||
@Route.post(
|
||||
@@ -273,15 +272,14 @@ class ProjectHandler:
|
||||
|
||||
pm = ProjectManager.instance()
|
||||
project = pm.get_project(request.match_info["project_id"])
|
||||
path = request.match_info["path"]
|
||||
path = os.path.normpath(path)
|
||||
path = os.path.normpath(request.match_info["path"])
|
||||
|
||||
# Raise error if user try to escape
|
||||
if path[0] == ".":
|
||||
if not is_safe_path(path, project.path):
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
path = os.path.join(project.path, path)
|
||||
|
||||
response.set_status(200)
|
||||
path = os.path.join(project.path, path)
|
||||
response.set_status(201)
|
||||
|
||||
try:
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
|
||||
@@ -207,7 +207,7 @@ class QEMUHandler:
|
||||
enable_kvm = qemu_manager.config.get_section_config("Qemu").getboolean("enable_kvm")
|
||||
if enable_kvm is not None:
|
||||
hardware_accel = enable_kvm
|
||||
if hardware_accel and "-no-kvm" not in vm.options and "-no-hax" not in vm.options:
|
||||
if hardware_accel and "-machine accel=tcg" not in vm.options:
|
||||
pm = ProjectManager.instance()
|
||||
if pm.check_hardware_virtualization(vm) is False:
|
||||
raise aiohttp.web.HTTPConflict(text="Cannot start VM with hardware acceleration (KVM/HAX) enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
|
||||
@@ -552,7 +552,8 @@ class QEMUHandler:
|
||||
async def upload_image(request, response):
|
||||
|
||||
qemu_manager = Qemu.instance()
|
||||
await qemu_manager.write_image(request.match_info["filename"], request.content)
|
||||
filename = os.path.normpath(request.match_info["filename"])
|
||||
await qemu_manager.write_image(filename, request.content)
|
||||
response.set_status(204)
|
||||
|
||||
@Route.get(
|
||||
@@ -566,15 +567,15 @@ class QEMUHandler:
|
||||
raw=True,
|
||||
description="Download Qemu image")
|
||||
async def download_image(request, response):
|
||||
filename = request.match_info["filename"]
|
||||
|
||||
filename = os.path.normpath(request.match_info["filename"])
|
||||
|
||||
# Raise error if user try to escape
|
||||
if filename[0] == "." or os.path.sep in filename:
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
qemu_manager = Qemu.instance()
|
||||
image_path = qemu_manager.get_abs_image_path(filename)
|
||||
|
||||
# Raise error if user try to escape
|
||||
if filename[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
await response.stream_file(image_path)
|
||||
|
||||
@Route.get(
|
||||
|
||||
@@ -24,6 +24,7 @@ from gns3server.schemas.version import VERSION_SCHEMA
|
||||
from gns3server.schemas.server_statistics import SERVER_STATISTICS_SCHEMA
|
||||
from gns3server.compute.port_manager import PortManager
|
||||
from gns3server.utils.cpu_percent import CpuPercent
|
||||
from gns3server.utils.path import get_default_project_directory
|
||||
from gns3server.version import __version__
|
||||
from aiohttp.web import HTTPConflict
|
||||
|
||||
@@ -61,7 +62,7 @@ class ServerHandler:
|
||||
load_average_percent = [int(x / psutil.cpu_count() * 100) for x in psutil.getloadavg()]
|
||||
memory_percent = int(psutil.virtual_memory().percent)
|
||||
swap_percent = int(psutil.swap_memory().percent)
|
||||
disk_usage_percent = int(psutil.disk_usage('/').percent)
|
||||
disk_usage_percent = int(psutil.disk_usage(get_default_project_directory()).percent)
|
||||
except psutil.Error as e:
|
||||
raise HTTPConflict(text="Psutil error detected: {}".format(e))
|
||||
response.json({"memory_total": memory_total,
|
||||
|
||||
@@ -64,6 +64,8 @@ class LinkHandler:
|
||||
link = await project.add_link()
|
||||
if "filters" in request.json:
|
||||
await link.update_filters(request.json["filters"])
|
||||
if "link_style" in request.json:
|
||||
await link.update_link_style(request.json["link_style"])
|
||||
if "suspend" in request.json:
|
||||
await link.update_suspend(request.json["suspend"])
|
||||
try:
|
||||
@@ -135,6 +137,8 @@ class LinkHandler:
|
||||
link = project.get_link(request.match_info["link_id"])
|
||||
if "filters" in request.json:
|
||||
await link.update_filters(request.json["filters"])
|
||||
if "link_style" in request.json:
|
||||
await link.update_link_style(request.json["link_style"])
|
||||
if "suspend" in request.json:
|
||||
await link.update_suspend(request.json["suspend"])
|
||||
if "nodes" in request.json:
|
||||
@@ -215,6 +219,7 @@ class LinkHandler:
|
||||
async def pcap(request, response):
|
||||
|
||||
project = await Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||
ssl_context = Controller.instance().ssl_context()
|
||||
link = project.get_link(request.match_info["link_id"])
|
||||
if not link.capturing:
|
||||
raise aiohttp.web.HTTPConflict(text="This link has no active packet capture")
|
||||
@@ -226,7 +231,7 @@ class LinkHandler:
|
||||
headers['Router-Host'] = request.host
|
||||
body = await request.read()
|
||||
|
||||
connector = aiohttp.TCPConnector(limit=None, force_close=True)
|
||||
connector = aiohttp.TCPConnector(limit=None, force_close=True, ssl_context=ssl_context)
|
||||
async with aiohttp.ClientSession(connector=connector, headers=headers) as session:
|
||||
async with session.request(request.method, pcap_streaming_url, timeout=None, data=body) as response:
|
||||
proxied_response = aiohttp.web.Response(headers=response.headers, status=response.status)
|
||||
|
||||
@@ -409,21 +409,19 @@ class NodeHandler:
|
||||
path = request.match_info["path"]
|
||||
path = force_unix_path(path)
|
||||
|
||||
|
||||
# Raise error if user try to escape
|
||||
if path[0] == ".":
|
||||
if path[0] == "." or "/../" in path:
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
node_type = node.node_type
|
||||
path = "/project-files/{}/{}/{}".format(node_type, node.id, path)
|
||||
|
||||
res = await node.compute.http_query("GET", "/projects/{project_id}/files{path}".format(project_id=project.id, path=path), timeout=None, raw=True)
|
||||
response.set_status(200)
|
||||
response.content_type = "application/octet-stream"
|
||||
response.enable_chunked_encoding()
|
||||
await response.prepare(request)
|
||||
await response.write(res.body)
|
||||
# await response.write_eof() #FIXME: shound't be needed anymore
|
||||
response.set_status(res.status)
|
||||
if res.status == 200:
|
||||
response.content_type = "application/octet-stream"
|
||||
response.enable_chunked_encoding()
|
||||
await response.prepare(request)
|
||||
await response.write(res.body)
|
||||
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/nodes/{node_id}/files/{path:.+}",
|
||||
@@ -446,14 +444,14 @@ class NodeHandler:
|
||||
path = force_unix_path(path)
|
||||
|
||||
# Raise error if user try to escape
|
||||
if path[0] == ".":
|
||||
if path[0] == "." or "/../" in path:
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
node_type = node.node_type
|
||||
path = "/project-files/{}/{}/{}".format(node_type, node.id, path)
|
||||
data = await request.content.read() #FIXME: are we handling timeout or large files correctly?
|
||||
await node.compute.http_query("POST", "/projects/{project_id}/files{path}".format(project_id=project.id, path=path), data=data, timeout=None, raw=True)
|
||||
response.set_status(201)
|
||||
res = await node.compute.http_query("POST", "/projects/{project_id}/files{path}".format(project_id=project.id, path=path), data=data, timeout=None, raw=True)
|
||||
response.set_status(res.status)
|
||||
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/nodes/{node_id}/console/ws",
|
||||
|
||||
@@ -28,6 +28,7 @@ from gns3server.controller import Controller
|
||||
from gns3server.controller.import_project import import_project
|
||||
from gns3server.controller.export_project import export_project
|
||||
from gns3server.utils.asyncio import aiozipstream
|
||||
from gns3server.utils.path import is_safe_path
|
||||
from gns3server.config import Config
|
||||
|
||||
|
||||
@@ -454,14 +455,12 @@ class ProjectHandler:
|
||||
|
||||
controller = Controller.instance()
|
||||
project = await controller.get_loaded_project(request.match_info["project_id"])
|
||||
path = request.match_info["path"]
|
||||
path = os.path.normpath(path).strip('/')
|
||||
path = os.path.normpath(request.match_info["path"])
|
||||
|
||||
# Raise error if user try to escape
|
||||
if path[0] == ".":
|
||||
if not is_safe_path(path, project.path):
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
path = os.path.join(project.path, path)
|
||||
|
||||
await response.stream_file(path)
|
||||
|
||||
@Route.post(
|
||||
@@ -480,15 +479,13 @@ class ProjectHandler:
|
||||
|
||||
controller = Controller.instance()
|
||||
project = await controller.get_loaded_project(request.match_info["project_id"])
|
||||
path = request.match_info["path"]
|
||||
path = os.path.normpath(path).strip("/")
|
||||
path = os.path.normpath(request.match_info["path"])
|
||||
|
||||
# Raise error if user try to escape
|
||||
if path[0] == ".":
|
||||
if not is_safe_path(path, project.path):
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
path = os.path.join(project.path, path)
|
||||
|
||||
response.set_status(200)
|
||||
response.set_status(201)
|
||||
|
||||
try:
|
||||
async with aiofiles.open(path, 'wb+') as f:
|
||||
|
||||
@@ -78,6 +78,22 @@ class ServerHandler:
|
||||
pass
|
||||
response.set_status(201)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/reload",
|
||||
description="Reload the local server",
|
||||
status_codes={
|
||||
200: "Server has reloaded"
|
||||
})
|
||||
async def reload(request, response):
|
||||
|
||||
from gns3server.web.web_server import WebServer
|
||||
server = WebServer.instance()
|
||||
try:
|
||||
asyncio.ensure_future(server.reload_server())
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
@Route.get(
|
||||
r"/version",
|
||||
description="Retrieve the server version number",
|
||||
@@ -231,7 +247,7 @@ Processus:
|
||||
try:
|
||||
psinfo = proc.as_dict(attrs=["name", "exe"])
|
||||
data += "* {} {}\n".format(psinfo["name"], psinfo["exe"])
|
||||
except psutil.NoSuchProcess:
|
||||
except (OSError, psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
|
||||
data += "\n\nProjects"
|
||||
|
||||
@@ -23,7 +23,6 @@ import urllib.parse
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.controller import Controller
|
||||
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -44,6 +43,24 @@ class SymbolHandler:
|
||||
controller = Controller.instance()
|
||||
response.json(controller.symbols.list())
|
||||
|
||||
@Route.get(
|
||||
r"/symbols/{symbol_id:.+}/dimensions",
|
||||
description="Get the symbol dimensions",
|
||||
status_codes={
|
||||
200: "Symbol dimensions returned"
|
||||
})
|
||||
async def get_dimensions(request, response):
|
||||
|
||||
controller = Controller.instance()
|
||||
symbol_id = urllib.parse.unquote(request.match_info["symbol_id"])
|
||||
try:
|
||||
width, height, _ = controller.symbols.get_size(symbol_id)
|
||||
symbol_dimensions = {'width': width, 'height': height}
|
||||
response.json(symbol_dimensions)
|
||||
except (KeyError, OSError, ValueError) as e:
|
||||
log.warning("Could not get symbol dimensions: {}".format(e))
|
||||
response.set_status(404)
|
||||
|
||||
@Route.get(
|
||||
r"/symbols/{symbol_id:.+}/raw",
|
||||
description="Get the symbol file",
|
||||
|
||||
@@ -92,7 +92,7 @@ class IndexHandler:
|
||||
filename = os.path.join('static', 'web-ui', filename)
|
||||
|
||||
# Raise error if user try to escape
|
||||
if filename[0] == ".":
|
||||
if filename[0] == "." or '/../' in filename:
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
static = get_resource(filename)
|
||||
|
||||
+2
-2
@@ -195,7 +195,7 @@ def kill_ghosts():
|
||||
if name in detect_process:
|
||||
proc.kill()
|
||||
log.warning("Killed ghost process %s", name)
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
except (OSError, psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ def run():
|
||||
server.run()
|
||||
except OSError as e:
|
||||
# This is to ignore OSError: [WinError 0] The operation completed successfully exception on Windows.
|
||||
if not sys.platform.startswith("win") and not e.winerror == 0:
|
||||
if not sys.platform.startswith("win") or not e.winerror == 0:
|
||||
raise
|
||||
except Exception as e:
|
||||
log.critical("Critical error while running the server: {}".format(e), exc_info=1)
|
||||
|
||||
@@ -41,6 +41,10 @@ GNS3VM_SETTINGS_SCHEMA = {
|
||||
"description": "The engine to use for the VM. Null to disable",
|
||||
"enum": ["vmware", "virtualbox", None]
|
||||
},
|
||||
"allocate_vcpus_ram": {
|
||||
"description": "Allocate vCPUS and RAM settings",
|
||||
"type": "boolean"
|
||||
},
|
||||
"vcpus": {
|
||||
"description": "Number of vCPUS affected to the VM",
|
||||
"type": "integer"
|
||||
|
||||
@@ -68,6 +68,27 @@ LINK_OBJECT_SCHEMA = {
|
||||
"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": FILTER_OBJECT_SCHEMA,
|
||||
"capturing": {
|
||||
"description": "Read only property. True if a capture running on the link",
|
||||
|
||||
Loaded 100 of 707 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user