mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-12 09:55:54 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5dd0414ab3 | ||
|
|
e8353e68bb | ||
|
|
23c63bbd4d | ||
|
|
dadf11f69b | ||
|
|
3efe753eee | ||
|
|
f48420af58 | ||
|
|
79bca29b93 | ||
|
|
0e4865e049 | ||
|
|
26567d9164 | ||
|
|
a8177d7afa | ||
|
|
a393e7f723 | ||
|
|
0df997d232 | ||
|
|
630afc5469 | ||
|
|
3e3e1df051 | ||
|
|
3a1ba8f42d | ||
|
|
0a72e0db87 | ||
|
|
e3b3427cc6 | ||
|
|
dde2003168 | ||
|
|
cfe8e9e85c | ||
|
|
1699ce5d1c | ||
|
|
d0850927d0 | ||
|
|
745532bf23 | ||
|
|
78cf0309a0 | ||
|
|
851fcf5c71 | ||
|
|
a80355998d | ||
|
|
e54d574e47 | ||
|
|
fe60c414b9 | ||
|
|
efbf7728ea | ||
|
|
061af38b5a | ||
|
|
f48549a997 | ||
|
|
958ab2294c | ||
|
|
dd89b09f84 | ||
|
|
642536a070 | ||
|
|
860ca3b35d | ||
|
|
96a0b52cf8 | ||
|
|
7c90c513d0 | ||
|
|
fe59c937d5 | ||
|
|
b48f5df53f | ||
|
|
3e2e8e61f7 | ||
|
|
068077c594 | ||
|
|
e08aebf1f0 | ||
|
|
cfbcc1194d | ||
|
|
035a078b5e | ||
|
|
cf14deb2fa | ||
|
|
e1fe34ca07 | ||
|
|
d3e55520d9 | ||
|
|
4477cd4dfd | ||
|
|
967798a7de | ||
|
|
61acb939a4 | ||
|
|
8c11b649e5 | ||
|
|
b14e2e73ed | ||
|
|
2235a8158f | ||
|
|
9afe756462 | ||
|
|
135c529d4b | ||
|
|
ce219e81ea | ||
|
|
a7412d1c87 |
No files matched your search
@@ -1,5 +1,35 @@
|
||||
# Change Log
|
||||
|
||||
## 2.1.1 22/12/2017
|
||||
|
||||
* Protect variable replacement for Qemu options. Escape double quotes.
|
||||
* Add proper exception when cannot find tunnel on QEMU, Fixes: #1241
|
||||
* Increase timeout for creation of image, Ref. #2239
|
||||
* Protect variable replacement for Qemu options.
|
||||
* Do not overwrites persistent Docker volumes. Fixes #2358.
|
||||
* Allow users to see an error when the server cannot stream a PCAP file.
|
||||
* Fix issue with Qemu + SPICE when IPv4 is not enabled.
|
||||
* Warn users if the GNS3 VM and local server are not in the same subnet. Fixes #1231.
|
||||
* Add missing appliance files.
|
||||
* Update appliance files.
|
||||
* Fix auto idle-pc from preferences.
|
||||
* Keep consistance of aiohttp.web.HTTPForbidden() execution
|
||||
* Make sure connected links are removed when a node is deleted.
|
||||
* Validate idle-pc values for auto idle-pc feature.
|
||||
* Fix error when updating packet filter on stopped Docker link. Fixes #1229.
|
||||
* Remotely close telnet console. Ref #2330
|
||||
* EthernetSwitch closing connections, Ref: gui/#2330
|
||||
* Export files from remote server, Fixes: gui/#2271
|
||||
* New option: require KVM. If false, Qemu VMs will not be prevented to run without KVM.
|
||||
* Implement variable replacement for Qemu VM options.
|
||||
* Avoid duplicate "-nographic" option.
|
||||
* Show qemu-img stdout in case of an error.
|
||||
* Use the correct NVRAM amount when pushing private config to IOU.
|
||||
* Check and fix corrupt Qemu disk images. Fixes #2301.
|
||||
* Update warning messages when connecting to non custom adapter for VMware VMs.
|
||||
* Fix "Can't use VirtualBox VM when an interface is managed by VirtualBox". Fixes #2335.
|
||||
* Add low disk space warning when creating a new project.
|
||||
|
||||
## 2.1.0 09/11/2017
|
||||
|
||||
* Fix typo in vcpus on VirtualBoxVM, fixes: #1213
|
||||
|
||||
@@ -63,3 +63,5 @@ license_check = True
|
||||
[Qemu]
|
||||
; !! Remember to add the gns3 user to the KVM group, otherwise you will not have read / write permssions to /dev/kvm !!
|
||||
enable_kvm = True
|
||||
; Require KVM to be installed in order to start VMs
|
||||
require_kvm = True
|
||||
@@ -24,6 +24,20 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "vEOS-lab-4.20.1F.vmdk",
|
||||
"version": "4.20.1F",
|
||||
"md5sum": "aadb6f3dbff28317f68cb4c4502d0db8",
|
||||
"filesize": 662044672,
|
||||
"download_url": "https://www.arista.com/en/support/software-download"
|
||||
},
|
||||
{
|
||||
"filename": "vEOS-lab-4.18.5M.vmdk",
|
||||
"version": "4.18.5M",
|
||||
"md5sum": "b1ee6268dbaf2b2276fd7a5286c7ce2b",
|
||||
"filesize": 623116288,
|
||||
"download_url": "https://www.arista.com/en/support/software-download"
|
||||
},
|
||||
{
|
||||
"filename": "vEOS-lab-4.18.1F.vmdk",
|
||||
"version": "4.18.1F",
|
||||
@@ -82,6 +96,20 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "4.20.1F",
|
||||
"images": {
|
||||
"hda_disk_image": "Aboot-veos-serial-8.0.0.iso",
|
||||
"hdb_disk_image": "vEOS-lab-4.20.1F.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "4.18.5M",
|
||||
"images": {
|
||||
"hda_disk_image": "Aboot-veos-serial-8.0.0.iso",
|
||||
"hdb_disk_image": "vEOS-lab-4.18.5M.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "4.18.1F",
|
||||
"images": {
|
||||
|
||||
@@ -19,6 +19,15 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "BSDRP-1.80-full-amd64-serial.img",
|
||||
"version": "1.80",
|
||||
"md5sum": "a4285be15ac85f67b3c7f044872a54b6",
|
||||
"filesize": 1000000000,
|
||||
"download_url": "https://bsdrp.net/downloads",
|
||||
"direct_download_url": "https://sourceforge.net/projects/bsdrp/files/BSD_Router_Project/1.80/amd64/BSDRP-1.80-full-amd64-serial.img.xz/download",
|
||||
"compression": "xz"
|
||||
},
|
||||
{
|
||||
"filename": "BSDRP-1.70-full-amd64-serial.img",
|
||||
"version": "1.70",
|
||||
@@ -30,6 +39,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "1.80",
|
||||
"images": {
|
||||
"hda_disk_image": "BSDRP-1.80-full-amd64-serial.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "1.70",
|
||||
"images": {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "Centos",
|
||||
"category": "guest",
|
||||
"description": "The CentOS Linux distribution is a stable, predictable, manageable and reproducible platform derived from the sources of Red Hat Enterprise Linux (RHEL). We are now looking to expand on that by creating the resources needed by other communities to come together and be able to build on the CentOS Linux platform. And today we start the process by delivering a clear governance model, increased transparency and access. In the coming weeks we aim to publish our own roadmap that includes variants of the core CentOS Linux.",
|
||||
"vendor_name": "CentOS Linux",
|
||||
"vendor_url": "https://www.centos.org/",
|
||||
"documentation_url": "https://wiki.centos.org/",
|
||||
"product_name": "Centos",
|
||||
"product_url": "https://www.centos.org/download/",
|
||||
"registry_version": 5,
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Username: osboxes.org\nPassword: osboxes.org",
|
||||
"port_name_format": "eth{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 1,
|
||||
"ram": 2048,
|
||||
"hda_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "spice",
|
||||
"boot_priority": "c",
|
||||
"kvm": "require",
|
||||
"options": "-vga qxl"
|
||||
},
|
||||
"images": [
|
||||
|
||||
{
|
||||
"filename": "CentOS 7-1611 (64bit).vmdk",
|
||||
"version": "7-1611",
|
||||
"md5sum": "1da15f6144eab25c8546f81dd1c34092",
|
||||
"filesize": 4365877248,
|
||||
"download_url": "http://www.osboxes.org/centos/"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "7-1611",
|
||||
"images": {
|
||||
"hda_disk_image": "CentOS 7-1611 (64bit).vmdk"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -22,6 +22,27 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "csr1000v-universalk9.16.07.01-serial.qcow2",
|
||||
"version": "16.7.1",
|
||||
"md5sum": "13adbfc2586d06c9802b9805168c0c44",
|
||||
"filesize": 882769920,
|
||||
"download_url": "https://software.cisco.com/download/release.html?mdfid=284364978&flowid=39582&softwareid=282046477&release=Fuji-16.7.1&relind=AVAILABLE&rellifecycle=ED&reltype=latest"
|
||||
},
|
||||
{
|
||||
"filename": "csr1000v-universalk9.16.06.01-serial.qcow2",
|
||||
"version": "16.6.1",
|
||||
"md5sum": "909e74446d3ff0b82c14327c0058fdc2",
|
||||
"filesize": 1566179328,
|
||||
"download_url": "https://software.cisco.com/download/release.html?mdfid=284364978&flowid=39582&softwareid=282046477&release=Denali-16.3.5&relind=AVAILABLE&rellifecycle=ED&reltype=latest"
|
||||
},
|
||||
{
|
||||
"filename": "csr1000v-universalk9.16.05.02-serial.qcow2",
|
||||
"version": "16.5.2",
|
||||
"md5sum": "59a84da28d59ee75176aa05ecde7f72a",
|
||||
"filesize": 1322385408,
|
||||
"download_url": "https://software.cisco.com/download/release.html?mdfid=284364978&flowid=39582&softwareid=282046477&release=Denali-16.3.5&relind=AVAILABLE&rellifecycle=ED&reltype=latest"
|
||||
},
|
||||
{
|
||||
"filename": "csr1000v-universalk9.16.5.1b-serial.qcow2",
|
||||
"version": "16.5.1b",
|
||||
@@ -66,6 +87,24 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "16.7.1",
|
||||
"images": {
|
||||
"hda_disk_image": "csr1000v-universalk9.16.07.01-serial.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "16.6.1",
|
||||
"images": {
|
||||
"hda_disk_image": "csr1000v-universalk9.16.06.01-serial.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "16.5.2",
|
||||
"images": {
|
||||
"hda_disk_image": "csr1000v-universalk9.16.05.02-serial.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "16.5.1b",
|
||||
"images": {
|
||||
@@ -89,13 +128,13 @@
|
||||
"images": {
|
||||
"hda_disk_image": "csr1000v-universalk9.16.3.1-build2.qcow2"
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "16.3.2",
|
||||
"images": {
|
||||
"hda_disk_image": "csr1000v-universalk9.16.03.02.qcow2"
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "16.4.1",
|
||||
"images": {
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
"options": "-smp 4"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "xrv9k-fullk9-x-6.2.25.qcow2",
|
||||
"version": "6.2.25",
|
||||
"md5sum": "3f54e62b6f7cedfb2607233e5e465766",
|
||||
"filesize": 1190723584,
|
||||
"download_url": "https://virl.mediuscorp.com/my-account/"
|
||||
},
|
||||
{
|
||||
"filename": "xrv9k-fullk9-x.qcow2-6.0.1",
|
||||
"version": "6.0.1",
|
||||
@@ -40,6 +47,18 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "6.2.25",
|
||||
"images": {
|
||||
"hda_disk_image": "xrv9k-fullk9-x-6.2.25.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.0.1",
|
||||
"images": {
|
||||
"hda_disk_image": "xrv9k-fullk9-x.qcow2-6.0.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.0.0",
|
||||
"images": {
|
||||
|
||||
@@ -21,6 +21,15 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "coreos_production_qemu_image.1520.8.0.img",
|
||||
"version": "1520.8.0",
|
||||
"md5sum": "a69fb2cd3ae475f9afbc268f7d391e83",
|
||||
"filesize": 842661888,
|
||||
"download_url": "http://stable.release.core-os.net/amd64-usr/1520.8.0/",
|
||||
"direct_download_url": "http://stable.release.core-os.net/amd64-usr/1520.8.0/coreos_production_qemu_image.img.bz2",
|
||||
"compression": "bzip2"
|
||||
},
|
||||
{
|
||||
"filename": "coreos_production_qemu_image.1465.7.0.img",
|
||||
"version": "1465.7.0",
|
||||
@@ -131,6 +140,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "1520.8.0",
|
||||
"images": {
|
||||
"hda_disk_image": "coreos_production_qemu_image.1520.8.0.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "1465.7.0",
|
||||
"images": {
|
||||
|
||||
@@ -23,12 +23,21 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "cumulus-linux-3.4.3-vx-amd64.qcow2",
|
||||
"version": "3.4.3",
|
||||
"md5sum": "fd9144cdab7cac66cf421a13c6f50ac8",
|
||||
"filesize": 988872704,
|
||||
"download_url": "https://cumulusnetworks.com/cumulus-vx/download/",
|
||||
"direct_download_url": "http://cumulusfiles.s3.amazonaws.com/cumulus-linux-3.4.3-vx-amd64.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "cumulus-linux-3.4.2-vx-amd64.qcow2",
|
||||
"version": "3.4.2",
|
||||
"md5sum": "ca844684784ceeee893d0cd76dc44e3b",
|
||||
"filesize": 1060700160,
|
||||
"download_url": "https://cumulusnetworks.com/cumulus-vx/download/"
|
||||
"download_url": "https://cumulusnetworks.com/cumulus-vx/download/",
|
||||
"direct_download_url": "http://cumulusfiles.s3.amazonaws.com/cumulus-linux-3.4.2-vx-amd64.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "cumulus-linux-3.4.1-vx-amd64.qcow2",
|
||||
@@ -116,6 +125,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "3.4.3",
|
||||
"images": {
|
||||
"hda_disk_image": "cumulus-linux-3.4.3-vx-amd64.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "3.4.2",
|
||||
"images": {
|
||||
|
||||
@@ -34,6 +34,20 @@
|
||||
"filesize": 30998528,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAD_KVM-V400-build0977-FORTINET.out.kvm-boot.qcow2",
|
||||
"version": "4.8.2",
|
||||
"md5sum": "285ca7a601a0d06bb893ef91ad7748fd",
|
||||
"filesize": 72876032,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAD_KVM-V400-build0970-FORTINET.out.kvm-boot.qcow2",
|
||||
"version": "4.8.1",
|
||||
"md5sum": "8f604b2a89ac3d9cc3d2d79d85b2d7ff",
|
||||
"filesize": 72351744,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAD_KVM-V400-build0937-FORTINET.out.kvm-boot.qcow2",
|
||||
"version": "4.8.0",
|
||||
@@ -41,6 +55,13 @@
|
||||
"filesize": 72089600,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAD_KVM-V400-build0858-FORTINET.out.kvm-boot.qcow2",
|
||||
"version": "4.7.4",
|
||||
"md5sum": "6d81b1b3df55174e4db8526d6cfd8b0e",
|
||||
"filesize": 63700992,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAD_KVM-V400-build0849-FORTINET.out.kvm-boot.qcow2",
|
||||
"version": "4.7.3",
|
||||
@@ -120,6 +141,20 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "4.8.2",
|
||||
"images": {
|
||||
"hda_disk_image": "FAD_KVM-V400-build0977-FORTINET.out.kvm-boot.qcow2",
|
||||
"hdb_disk_image": "FAD_KVM-v400-FORTINET.out.kvm-data.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "4.8.1",
|
||||
"images": {
|
||||
"hda_disk_image": "FAD_KVM-V400-build0970-FORTINET.out.kvm-boot.qcow2",
|
||||
"hdb_disk_image": "FAD_KVM-v400-FORTINET.out.kvm-data.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "4.8.0",
|
||||
"images": {
|
||||
@@ -127,6 +162,13 @@
|
||||
"hdb_disk_image": "FAD_KVM-v400-FORTINET.out.kvm-data.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "4.7.4",
|
||||
"images": {
|
||||
"hda_disk_image": "FAD_KVM-V400-build0858-FORTINET.out.kvm-boot.qcow2",
|
||||
"hdb_disk_image": "FAD_KVM-v400-FORTINET.out.kvm-data.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "4.7.3",
|
||||
"images": {
|
||||
|
||||
@@ -33,6 +33,13 @@
|
||||
"filesize": 106905600,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAZ_VM64_KVM-v5-build1225-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.4.4",
|
||||
"md5sum": "69cddb5c3e49bab3dc287353d8600b45",
|
||||
"filesize": 88715264,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAZ_VM64_KVM-v5-build1187-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.4.3",
|
||||
@@ -106,6 +113,13 @@
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.4.4",
|
||||
"images": {
|
||||
"hda_disk_image": "FAZ_VM64_KVM-v5-build1225-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.4.3",
|
||||
"images": {
|
||||
|
||||
@@ -26,6 +26,27 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "FAC_VM_KVM-v500-build0091-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.1.2",
|
||||
"md5sum": "7bdafd32db552954c4c7fe60296fc600",
|
||||
"filesize": 71135232,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAC_VM_KVM-v500-build0086-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.1.1",
|
||||
"md5sum": "960017582fe16e7ce7ab9602600e65fe",
|
||||
"filesize": 71819264,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAC_VM_KVM-v500-build0083-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.1.0",
|
||||
"md5sum": "eec53c2dbe5d00c8ce2a7ca50226325a",
|
||||
"filesize": 72495104,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAC_VM_KVM-v500-build0012-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.0.0",
|
||||
@@ -42,6 +63,27 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "5.1.2",
|
||||
"images": {
|
||||
"hda_disk_image": "FAC_VM_KVM-v500-build0091-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "FAC_VM_KVM-v500-DATADRIVE.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.1.1",
|
||||
"images": {
|
||||
"hda_disk_image": "FAC_VM_KVM-v500-build0086-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "FAC_VM_KVM-v500-DATADRIVE.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.1.0",
|
||||
"images": {
|
||||
"hda_disk_image": "FAC_VM_KVM-v500-build0083-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "FAC_VM_KVM-v500-DATADRIVE.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.0.0",
|
||||
"images": {
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "FCHKVM-v400-build0213-FORTINET.out.kvm.qcow2",
|
||||
"version": "4.2.5",
|
||||
"md5sum": "78db88447f29f363b4ba8e4833474637",
|
||||
"filesize": 27508736,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FCHKVM-v400-build0204-FORTINET.out.kvm.qcow2",
|
||||
"version": "4.2.4",
|
||||
@@ -85,6 +92,13 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "4.2.5",
|
||||
"images": {
|
||||
"hda_disk_image": "FCHKVM-v400-build0213-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "empty100G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "4.2.4",
|
||||
"images": {
|
||||
|
||||
@@ -47,6 +47,13 @@
|
||||
"filesize": 38760448,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FGT_VM64_KVM-v5-build1165-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.4.6",
|
||||
"md5sum": "4429f1f0f2cce4a8781354a9eb745c61",
|
||||
"filesize": 38457344,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FGT_VM64_KVM-v5-build1138-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.4.5",
|
||||
@@ -162,6 +169,13 @@
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.4.6",
|
||||
"images": {
|
||||
"hda_disk_image": "FGT_VM64_KVM-v5-build1165-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.4.5",
|
||||
"images": {
|
||||
|
||||
@@ -26,6 +26,20 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "FML_VMKV-64-v54-build0707-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.4.2",
|
||||
"md5sum": "b51260cc3e408bf1352a204b8370254b",
|
||||
"filesize": 92864512,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FML_VMKV-64-v54-build0704-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.4.1",
|
||||
"md5sum": "1f6553e182512cc87e20f47cc2b65abf",
|
||||
"filesize": 94568448,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FML_VMKV-64-v54-build0692-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.4.0",
|
||||
@@ -33,6 +47,13 @@
|
||||
"filesize": 101253120,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FML_VMKV-64-v53-build0648-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.3.11",
|
||||
"md5sum": "bd34a81c1bb6772c7e4919620027a5d4",
|
||||
"filesize": 88670208,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FML_VMKV-64-v53-build0643-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.3.10",
|
||||
@@ -106,6 +127,20 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "5.4.2",
|
||||
"images": {
|
||||
"hda_disk_image": "FML_VMKV-64-v54-build0707-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.4.1",
|
||||
"images": {
|
||||
"hda_disk_image": "FML_VMKV-64-v54-build0704-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.4.0",
|
||||
"images": {
|
||||
@@ -113,6 +148,13 @@
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.3.11",
|
||||
"images": {
|
||||
"hda_disk_image": "FML_VMKV-64-v53-build0648-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.3.10",
|
||||
"images": {
|
||||
|
||||
@@ -33,6 +33,13 @@
|
||||
"filesize": 108363776,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FMG_VM64_KVM-v5-build1225-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.4.4",
|
||||
"md5sum": "53bc6e320fe7bde5d2b636bde95a910c",
|
||||
"filesize": 89911296,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FMG_VM64_KVM-v5-build1187-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.4.3",
|
||||
@@ -106,6 +113,13 @@
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.4.4",
|
||||
"images": {
|
||||
"hda_disk_image": "FMG_VM64_KVM-v5-build1225-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.4.3",
|
||||
"images": {
|
||||
|
||||
@@ -40,6 +40,15 @@
|
||||
"direct_download_url": "https://download.freebsd.org/ftp/releases/VM-IMAGES/11.0-RELEASE/amd64/Latest/FreeBSD-11.0-RELEASE-amd64.qcow2.xz",
|
||||
"compression": "xz"
|
||||
},
|
||||
{
|
||||
"filename": "FreeBSD-10.4-RELEASE-amd64.qcow2",
|
||||
"version": "10.4",
|
||||
"md5sum": "ad498873733c57d1f6d890d587a11e3c",
|
||||
"filesize": 1013448704,
|
||||
"download_url": "https://www.freebsd.org/where.html",
|
||||
"direct_download_url": "https://download.freebsd.org/ftp/releases/VM-IMAGES/10.4-RELEASE/amd64/Latest/FreeBSD-10.4-RELEASE-amd64.qcow2.xz",
|
||||
"compression": "xz"
|
||||
},
|
||||
{
|
||||
"filename": "FreeBSD-10.3-RELEASE-amd64.qcow2",
|
||||
"version": "10.3",
|
||||
@@ -63,6 +72,12 @@
|
||||
"hda_disk_image": "FreeBSD-11.0-RELEASE-amd64.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "10.4",
|
||||
"images": {
|
||||
"hda_disk_image": "FreeBSD-10.4-RELEASE-amd64.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "10.3",
|
||||
"images": {
|
||||
|
||||
@@ -24,6 +24,14 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "FreeNAS-11.0-U4.iso",
|
||||
"version": "11.0-U4",
|
||||
"md5sum": "4c210f1a6510d1fa95257d81ef569ff8",
|
||||
"filesize": 567312384,
|
||||
"download_url": "http://www.freenas.org/download/",
|
||||
"direct_download_url": "http://download.freenas.org/11/11.0-U4/x64/FreeNAS-11.0-U4.iso"
|
||||
},
|
||||
{
|
||||
"filename": "FreeNAS-9.10.1-U4.iso",
|
||||
"version": "9.10",
|
||||
@@ -42,6 +50,14 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "11.0",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2",
|
||||
"cdrom_image": "FreeNAS-11.0-U4.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "9.10",
|
||||
"images": {
|
||||
|
||||
@@ -23,6 +23,13 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "VSR1000_HPE-CMW710-R0327L01-X64.qco",
|
||||
"version": "7.10.R0327L01",
|
||||
"md5sum": "907de5140a4a029afe1c517cfc27ecde",
|
||||
"filesize": 138739712,
|
||||
"download_url": "https://h10145.www1.hp.com/Downloads/DownloadSoftware.aspx?SoftwareReleaseUId=22702&ProductNumber=JG811AAE&lang=en&cc=us&prodSeriesId=5443163&SaidNumber="
|
||||
},
|
||||
{
|
||||
"filename": "VSR1000_HPE-CMW710-R0326-X64.qco",
|
||||
"version": "7.10.R0326",
|
||||
@@ -74,6 +81,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "7.10.R0327L01",
|
||||
"images": {
|
||||
"hda_disk_image": "VSR1000_HPE-CMW710-R0327L01-X64.qco"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "7.10.R0326",
|
||||
"images": {
|
||||
|
||||
@@ -24,6 +24,15 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ipfire-2.19.1gb-ext4-scon.x86_64-full-core116.img",
|
||||
"version": "2.19.116",
|
||||
"md5sum": "2a8df99d117a0dbfb67870494c0c67cd",
|
||||
"filesize": 1063256064,
|
||||
"download_url": "http://www.ipfire.org/download",
|
||||
"direct_download_url": "https://downloads.ipfire.org/releases/ipfire-2.x/2.19-core116/ipfire-2.19.1gb-ext4-scon.x86_64-full-core116.img.gz",
|
||||
"compression": "gzip"
|
||||
},
|
||||
{
|
||||
"filename": "ipfire-2.19.1gb-ext4-scon.x86_64-full-core111.img",
|
||||
"version": "2.19.111",
|
||||
@@ -44,6 +53,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "2.19.116",
|
||||
"images": {
|
||||
"hda_disk_image": "ipfire-2.19.1gb-ext4-scon.x86_64-full-core116.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2.19.111",
|
||||
"images": {
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
"options": "-smp 2"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "LoadMaster-VLM-7.2.40.0.15707.RELEASE-Linux-KVM-XEN-FREE.disk",
|
||||
"version": "7.2.40.0",
|
||||
"md5sum": "4284a80141f7974d082a2eed91ec6216",
|
||||
"filesize": 17179869185,
|
||||
"download_url": "http://freeloadbalancer.com/download/"
|
||||
},
|
||||
{
|
||||
"filename": "LoadMaster-VLM-7.2.38.0.14750.RELEASE-Linux-KVM-XEN.disk",
|
||||
"version": "7.2.38.0",
|
||||
@@ -56,6 +63,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "7.2.40.0",
|
||||
"images": {
|
||||
"hda_disk_image": "LoadMaster-VLM-7.2.40.0.15707.RELEASE-Linux-KVM-XEN-FREE.disk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "7.2.38.0",
|
||||
"images": {
|
||||
|
||||
@@ -24,6 +24,14 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "kerio-connect-appliance-9.2.5-3336-p3-vmware-amd64-disk1.vmdk",
|
||||
"version": "9.2.5p3",
|
||||
"md5sum": "f2a202f29e71dc6e8bebce4c05a9e44d",
|
||||
"filesize": 824496128,
|
||||
"download_url": "http://www.kerio.com/support/kerio-connect",
|
||||
"direct_download_url": "http://cdn.kerio.com/dwn/connect/connect-9.2.5-3336/kerio-connect-appliance-9.2.5-3336-p3-vmware-amd64-disk1.vmdk"
|
||||
},
|
||||
{
|
||||
"filename": "kerio-connect-appliance-9.2.4-3252-vmware-amd64-disk1.vmdk",
|
||||
"version": "9.2.4",
|
||||
@@ -59,6 +67,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "9.2.5",
|
||||
"images": {
|
||||
"hda_disk_image": "kerio-connect-appliance-9.2.5-3336-p3-vmware-amd64-disk1.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "9.2.4",
|
||||
"images": {
|
||||
|
||||
@@ -23,6 +23,14 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "kerio-control-appliance-9.2.4-2223-vmware-disk1.vmdk",
|
||||
"version": "9.2.4",
|
||||
"md5sum": "20970f3638c7ca5603c2afbe56e89421",
|
||||
"filesize": 191687168,
|
||||
"download_url": "http://www.kerio.com/support/kerio-control",
|
||||
"direct_download_url": "http://cdn.kerio.com/dwn/control/control-9.2.4-2223/kerio-control-appliance-9.2.4-2223-vmware-disk1.vmdk"
|
||||
},
|
||||
{
|
||||
"filename": "kerio-control-appliance-9.2.3-2219-vmware-disk1.vmdk",
|
||||
"version": "9.2.3",
|
||||
@@ -55,6 +63,12 @@
|
||||
"direct_download_url": "http://cdn.kerio.com/dwn/control/control-9.1.4-1535/kerio-control-appliance-9.1.4-1535-vmware.vmdk" }
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "9.2.4",
|
||||
"images": {
|
||||
"hda_disk_image": "kerio-control-appliance-9.2.4-2223-vmware-disk1.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "9.2.3",
|
||||
"images": {
|
||||
|
||||
@@ -23,6 +23,13 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "Loadbalancer.org_Enterprise_VA-8.3-disk1.qcow2",
|
||||
"version": "8.3",
|
||||
"md5sum": "f0e41f39a5cab47990edc0509c579bac",
|
||||
"filesize": 368332288,
|
||||
"download_url": "https://loadbalancer.org/resources/free-trial"
|
||||
},
|
||||
{
|
||||
"filename": "Loadbalancer.org_Enterprise_VA-8.2-disk1.qcow2",
|
||||
"version": "8.2",
|
||||
@@ -32,6 +39,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "8.3",
|
||||
"images": {
|
||||
"hda_disk_image": "Loadbalancer.org_Enterprise_VA-8.3-disk1.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "8.2",
|
||||
"images": {
|
||||
|
||||
@@ -26,6 +26,15 @@
|
||||
"options": "-nographic"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "chr-6.40.5.img",
|
||||
"version": "6.40.5",
|
||||
"md5sum": "5d3bef219a859d417fea704ae7109eb7",
|
||||
"filesize": 134217728,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download2.mikrotik.com/routeros/6.40.5/chr-6.40.5.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.40.3.img",
|
||||
"version": "6.40.3",
|
||||
@@ -226,6 +235,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "6.40.5",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.40.5.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.40.3",
|
||||
"images": {
|
||||
|
||||
@@ -22,6 +22,15 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "PacketFenceZEN_USB-7.3.0.img",
|
||||
"version": "7.3.0",
|
||||
"md5sum": "dfeb8a97bba2e475ce418b02327c0ea1",
|
||||
"filesize": 3221225472,
|
||||
"download_url": "https://packetfence.org/download.html#/zen",
|
||||
"direct_download_url": "http://sourceforge.net/projects/packetfence/files/PacketFence%20ZEN/7.3.0/PacketFenceZEN_USB-7.3.0.tar.bz2/download",
|
||||
"compression": "bzip2"
|
||||
},
|
||||
{
|
||||
"filename": "PacketFenceZEN_USB-7.1.0.img",
|
||||
"version": "7.1.0",
|
||||
@@ -87,6 +96,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "7.3.0",
|
||||
"images": {
|
||||
"hda_disk_image": "PacketFenceZEN_USB-7.3.0.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "7.1.0",
|
||||
"images": {
|
||||
|
||||
@@ -22,6 +22,13 @@
|
||||
"process_priority": "normal"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "pfSense-CE-2.3.5-RELEASE-2g-amd64-nanobsd.img",
|
||||
"version": "2.3.5",
|
||||
"md5sum": "b6cb76adba3e1113892f84ea01894228",
|
||||
"filesize": 1989969408,
|
||||
"download_url": "https://www.pfsense.org/download/mirror.php?section=downloads"
|
||||
},
|
||||
{
|
||||
"filename": "pfSense-CE-2.3.4-RELEASE-2g-amd64-nanobsd.img",
|
||||
"version": "2.3.4",
|
||||
@@ -66,6 +73,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "2.3.5",
|
||||
"images": {
|
||||
"hda_disk_image": "pfSense-CE-2.3.5-RELEASE-2g-amd64-nanobsd.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2.3.4",
|
||||
"images": {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"name": "Security Onion",
|
||||
"category": "guest",
|
||||
"description": "Security Onion is a Linux distro for intrusion detection, network security monitoring, and log management. It’s based on Ubuntu and contains Snort, Suricata, Bro, OSSEC, Sguil, Squert, ELSA, Xplico, NetworkMiner, and many other security tools. The easy-to-use Setup wizard allows you to build an army of distributed sensors for your enterprise in minutes!",
|
||||
"vendor_name": "Security Onion Solutions, LLC",
|
||||
"vendor_url": "https://securityonion.net/",
|
||||
"documentation_url": "https://github.com/Security-Onion-Solutions/security-onion/wiki",
|
||||
"product_name": "Security Onion",
|
||||
"product_url": "https://securityonion.net/",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "Brent Stewart",
|
||||
"maintainer_email": "brent@stewart.tc",
|
||||
"usage": "Your default account will have sudo priviledges. Squil and Squert username and password are configured in the Setup wizard. MySQL root is set to null. For more info see https://github.com/Security-Onion-Solutions/security-onion/wiki/Passwords.",
|
||||
"symbol": "securityonion-logo.png",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 2,
|
||||
"ram": 3072,
|
||||
"arch": "i386",
|
||||
"console_type": "telnet",
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "securityonion-14.04.5.4.iso",
|
||||
"version": "14.04.5.4",
|
||||
"md5sum": "9c7cab756b675beb10de4274a3ad3bc6",
|
||||
"filesize": 1874853888,
|
||||
"download_url": "https://github.com/Security-Onion-Solutions/security-onion/releases/download/v14.04.5.4_20171031/securityonion-14.04.5.4.iso",
|
||||
"direct_download_url": "https://github.com/Security-Onion-Solutions/security-onion/releases/download/v14.04.5.4_20171031/securityonion-14.04.5.4.iso"
|
||||
},
|
||||
{
|
||||
"filename": "securityonion-14.04.5.3.iso",
|
||||
"version": "14.04.5.3",
|
||||
"md5sum": "fb80ccb2d3c0f3f511823fa5858f87d1",
|
||||
"filesize": 1889533952,
|
||||
"download_url": "https://github.com/Security-Onion-Solutions/security-onion/releases/download/v14.04.5.4_20171031/securityonion-14.04.5.3.iso",
|
||||
"direct_download_url": "https://github.com/Security-Onion-Solutions/security-onion/releases/download/v14.04.5.4_20171031/securityonion-14.04.5.3.iso"
|
||||
},
|
||||
{
|
||||
"filename": "empty30G.qcow2",
|
||||
"version": "1.0",
|
||||
"md5sum": "3411a599e822f2ac6be560a26405821a",
|
||||
"filesize": 197120,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%30disk/",
|
||||
"direct_download_url": "http://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty30G.qcow2/download"
|
||||
}
|
||||
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "14.04.5.4",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2",
|
||||
"cdrom_image": "securityonion-14.04.5.4.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "14.04.5.3",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2",
|
||||
"cdrom_image": "securityonion-14.04.5.3.iso"
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
@@ -24,6 +24,14 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "zentyal-5.0.1-development-amd64.iso",
|
||||
"version": "5.0.1",
|
||||
"md5sum": "1ac74be6563f0b21b337c274e62cdd32",
|
||||
"filesize": 953155584,
|
||||
"download_url": "http://download.zentyal.com/",
|
||||
"direct_download_url": "http://download.zentyal.com/zentyal-5.0.1-development-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "zentyal-5.0-development-amd64.iso",
|
||||
"version": "5.0",
|
||||
@@ -66,6 +74,13 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "5.0.1",
|
||||
"images": {
|
||||
"hda_disk_image": "empty100G.qcow2",
|
||||
"cdrom_image": "zentyal-5.0.1-development-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.0",
|
||||
"images": {
|
||||
|
||||
@@ -20,15 +20,32 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ZeroShell-3.8.0-X86-USB.img",
|
||||
"version": "3.8.0",
|
||||
"md5sum": "a16d584c831f3e88ea442a2343d71cfa",
|
||||
"filesize": 1992294400,
|
||||
"download_url": "http://www.zeroshell.org/download/",
|
||||
"direct_download_url": "http://www.zeroshell.net/listing/ZeroShell-3.8.0-X86-USB.img.gz",
|
||||
"compression": "gzip"
|
||||
},
|
||||
{
|
||||
"filename": "ZeroShell-3.7.1-USB.img",
|
||||
"version": "3.7.1",
|
||||
"md5sum": "22e739a24dc1c233d3eca5d8fedc97c8",
|
||||
"filesize": 1992294400,
|
||||
"download_url": "http://www.zeroshell.org/download/"
|
||||
"download_url": "http://www.zeroshell.org/download/",
|
||||
"direct_download_url": "http://www.zeroshell.net/listing/ZeroShell-3.7.1-USB.img.gz",
|
||||
"compression": "gzip"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "3.8.0",
|
||||
"images": {
|
||||
"hda_disk_image": "ZeroShell-3.8.0-X86-USB.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "3.7.1",
|
||||
"images": {
|
||||
|
||||
@@ -335,8 +335,10 @@ class BaseManager:
|
||||
:returns: Node instance
|
||||
"""
|
||||
|
||||
node = yield from self.close_node(node_id)
|
||||
node.project.emit("node.deleted", node)
|
||||
try:
|
||||
node = yield from self.close_node(node_id)
|
||||
finally:
|
||||
node.project.emit("node.deleted", node)
|
||||
yield from node.project.remove_node(node)
|
||||
if node.id in self._nodes:
|
||||
del self._nodes[node.id]
|
||||
@@ -537,8 +539,8 @@ class BaseManager:
|
||||
directory = self.get_images_directory()
|
||||
path = os.path.abspath(os.path.join(directory, *os.path.split(filename)))
|
||||
if os.path.commonprefix([directory, path]) != directory:
|
||||
raise aiohttp.web.HTTPForbidden(text="Could not write image: {}, {} is forbiden".format(filename, path))
|
||||
log.info("Writting image file %s", path)
|
||||
raise aiohttp.web.HTTPForbidden(text="Could not write image: {}, {} is forbidden".format(filename, path))
|
||||
log.info("Writing image file %s", path)
|
||||
try:
|
||||
remove_checksum(path)
|
||||
# We store the file under his final name only when the upload is finished
|
||||
|
||||
@@ -236,6 +236,7 @@ class DockerVM(BaseNode):
|
||||
"""
|
||||
path = os.path.join(self.working_dir, "etc", "network")
|
||||
os.makedirs(path, exist_ok=True)
|
||||
open(os.path.join(path, ".gns3_perms"), 'a').close()
|
||||
os.makedirs(os.path.join(path, "if-up.d"), exist_ok=True)
|
||||
os.makedirs(os.path.join(path, "if-down.d"), exist_ok=True)
|
||||
os.makedirs(os.path.join(path, "if-pre-up.d"), exist_ok=True)
|
||||
@@ -749,9 +750,10 @@ class DockerVM(BaseNode):
|
||||
:param nio: NIO instance to add to the adapter
|
||||
"""
|
||||
|
||||
bridge_name = 'bridge{}'.format(adapter_number)
|
||||
if bridge_name in self._bridges:
|
||||
yield from self._ubridge_apply_filters(bridge_name, nio.filters)
|
||||
if self.ubridge:
|
||||
bridge_name = 'bridge{}'.format(adapter_number)
|
||||
if bridge_name in self._bridges:
|
||||
yield from self._ubridge_apply_filters(bridge_name, nio.filters)
|
||||
|
||||
@asyncio.coroutine
|
||||
def adapter_remove_nio_binding(self, adapter_number):
|
||||
|
||||
@@ -35,17 +35,17 @@ do
|
||||
mkdir -p "$i"
|
||||
|
||||
# Copy original files if destination is empty (first start)
|
||||
[ "$(ls -A "/gns3volumes$i")" ] || cp -a "$i/." "/gns3volumes$i"
|
||||
if [ ! -f "/gns3volumes$i/.gns3_perms" ]; then
|
||||
cp -a "$i/." "/gns3volumes$i"
|
||||
touch "/gns3volumes$i/.gns3_perms"
|
||||
fi
|
||||
|
||||
mount --bind "/gns3volumes$i" "$i"
|
||||
if [ -f "$i/.gns3_perms" ]
|
||||
then
|
||||
while IFS=: read PERMS OWNER GROUP FILE
|
||||
do
|
||||
[ -L "$FILE" ] || chmod "$PERMS" "$FILE"
|
||||
chown -h "${OWNER}:${GROUP}" "$FILE"
|
||||
done < "$i/.gns3_perms"
|
||||
fi
|
||||
while IFS=: read PERMS OWNER GROUP FILE
|
||||
do
|
||||
[ -L "$FILE" ] || chmod "$PERMS" "$FILE"
|
||||
chown -h "${OWNER}:${GROUP}" "$FILE"
|
||||
done < "$i/.gns3_perms"
|
||||
done
|
||||
|
||||
|
||||
|
||||
@@ -29,16 +29,15 @@ import asyncio
|
||||
import tempfile
|
||||
import logging
|
||||
import glob
|
||||
import re
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
from gns3server.utils.interfaces import interfaces, is_interface_up
|
||||
from gns3server.utils.images import md5sum
|
||||
from gns3server.utils.asyncio import wait_run_in_executor
|
||||
from gns3server.utils import parse_version
|
||||
from uuid import UUID, uuid4
|
||||
from uuid import uuid4
|
||||
from ..base_manager import BaseManager
|
||||
from ..project_manager import ProjectManager
|
||||
from ..port_manager import PortManager
|
||||
from .dynamips_error import DynamipsError
|
||||
from .hypervisor import Hypervisor
|
||||
@@ -574,6 +573,9 @@ class Dynamips(BaseManager):
|
||||
raise DynamipsError("No Idle-PC values found")
|
||||
|
||||
for idlepc in idlepcs:
|
||||
match = re.search(r"^0x[0-9a-f]{8}$", idlepc.split()[0])
|
||||
if not match:
|
||||
continue
|
||||
yield from vm.set_idlepc(idlepc.split()[0])
|
||||
log.debug("Auto Idle-PC: trying idle-PC value {}".format(vm.idlepc))
|
||||
start_time = time.time()
|
||||
|
||||
@@ -166,8 +166,8 @@ class EthernetSwitch(Device):
|
||||
|
||||
self._telnet_shell = EthernetSwitchConsole(self)
|
||||
self._telnet_shell.prompt = self._name + '> '
|
||||
telnet = create_telnet_shell(self._telnet_shell)
|
||||
self._telnet_server = (yield from asyncio.start_server(telnet.run, self._manager.port_manager.console_host, self.console))
|
||||
self._telnet = create_telnet_shell(self._telnet_shell)
|
||||
self._telnet_server = (yield from asyncio.start_server(self._telnet.run, self._manager.port_manager.console_host, self.console))
|
||||
|
||||
self._hypervisor.devices.append(self)
|
||||
|
||||
@@ -214,7 +214,9 @@ class EthernetSwitch(Device):
|
||||
"""
|
||||
Deletes this Ethernet switch.
|
||||
"""
|
||||
|
||||
yield from self._telnet.close()
|
||||
self._telnet_server.close()
|
||||
|
||||
for nio in self._nios.values():
|
||||
if nio:
|
||||
yield from nio.close()
|
||||
|
||||
@@ -65,7 +65,7 @@ class IOUVM(BaseNode):
|
||||
:param console: TCP console port
|
||||
"""
|
||||
|
||||
def __init__(self, name, node_id, project, manager, console=None):
|
||||
def __init__(self, name, node_id, project, manager, path=None, console=None):
|
||||
|
||||
super().__init__(name, node_id, project, manager, console=console)
|
||||
|
||||
@@ -73,8 +73,8 @@ class IOUVM(BaseNode):
|
||||
self._telnet_server = None
|
||||
self._iou_stdout_file = ""
|
||||
self._started = False
|
||||
self._path = None
|
||||
self._nvram_watcher = None
|
||||
self._path = self.manager.get_abs_image_path(path)
|
||||
|
||||
# IOU settings
|
||||
self._ethernet_adapters = []
|
||||
@@ -137,6 +137,7 @@ class IOUVM(BaseNode):
|
||||
"""
|
||||
|
||||
self._path = self.manager.get_abs_image_path(path)
|
||||
log.info('IOU "{name}" [{id}]: IOU image updated to "{path}"'.format(name=self._name, id=self._id, path=self._path))
|
||||
|
||||
@property
|
||||
def use_default_iou_values(self):
|
||||
@@ -162,6 +163,28 @@ class IOUVM(BaseNode):
|
||||
else:
|
||||
log.info('IOU "{name}" [{id}]: does not use the default IOU image values'.format(name=self._name, id=self._id))
|
||||
|
||||
@asyncio.coroutine
|
||||
def update_default_iou_values(self):
|
||||
"""
|
||||
Finds the default RAM and NVRAM values for the IOU image.
|
||||
"""
|
||||
|
||||
try:
|
||||
output = yield from gns3server.utils.asyncio.subprocess_check_output(self._path, "-h", cwd=self.working_dir, stderr=True)
|
||||
match = re.search("-n <n>\s+Size of nvram in Kb \(default ([0-9]+)KB\)", output)
|
||||
if match:
|
||||
self.nvram = int(match.group(1))
|
||||
match = re.search("-m <n>\s+Megabytes of router memory \(default ([0-9]+)MB\)", output)
|
||||
if match:
|
||||
self.ram = int(match.group(1))
|
||||
except (ValueError, OSError, subprocess.SubprocessError) as e:
|
||||
log.warning("could not find default RAM and NVRAM values for {}: {}".format(os.path.basename(self._path), e))
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
yield from self.update_default_iou_values()
|
||||
|
||||
def _check_requirements(self):
|
||||
"""
|
||||
Checks the IOU image.
|
||||
@@ -479,6 +502,9 @@ class IOUVM(BaseNode):
|
||||
yield from self._start_ubridge()
|
||||
|
||||
self._create_netmap_config()
|
||||
if self.use_default_iou_values:
|
||||
# make sure we have the default nvram amount to correctly push the configs
|
||||
yield from self.update_default_iou_values()
|
||||
self._push_configs_to_nvram()
|
||||
|
||||
# check if there is enough RAM to run
|
||||
|
||||
@@ -16,9 +16,14 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import aiohttp
|
||||
import psutil
|
||||
import platform
|
||||
from .project import Project
|
||||
from uuid import UUID
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProjectManager:
|
||||
|
||||
@@ -70,6 +75,26 @@ class ProjectManager:
|
||||
raise aiohttp.web.HTTPNotFound(text="Project ID {} doesn't exist".format(project_id))
|
||||
return self._projects[project_id]
|
||||
|
||||
def _check_available_disk_space(self, project):
|
||||
"""
|
||||
Sends a warning notification if disk space is getting low.
|
||||
|
||||
:param project: project instance
|
||||
"""
|
||||
|
||||
try:
|
||||
used_disk_space = psutil.disk_usage(project.path).percent
|
||||
except FileNotFoundError:
|
||||
log.warning('Could not find "{}" when checking for used disk space'.format(project.path))
|
||||
return
|
||||
# send a warning if used disk space is >= 90%
|
||||
if used_disk_space >= 90:
|
||||
message = 'Only {}% or less of disk space detected in "{}" on "{}"'.format(used_disk_space,
|
||||
project.path,
|
||||
platform.node())
|
||||
log.warning(message)
|
||||
project.emit("log.warning", {"message": message})
|
||||
|
||||
def create_project(self, name=None, project_id=None, path=None):
|
||||
"""
|
||||
Create a project and keep a references to it in project manager.
|
||||
@@ -80,6 +105,7 @@ class ProjectManager:
|
||||
if project_id is not None and project_id in self._projects:
|
||||
return self._projects[project_id]
|
||||
project = Project(name=name, project_id=project_id, path=path)
|
||||
self._check_available_disk_space(project)
|
||||
self._projects[project.id] = project
|
||||
return project
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import gns3server
|
||||
import subprocess
|
||||
|
||||
from gns3server.utils import parse_version
|
||||
from gns3server.utils.asyncio import subprocess_check_output
|
||||
from .qemu_error import QemuError
|
||||
from ..adapters.ethernet_adapter import EthernetAdapter
|
||||
from ..nios.nio_udp import NIOUDP
|
||||
@@ -74,6 +75,7 @@ class QemuVM(BaseNode):
|
||||
self._cpulimit_process = None
|
||||
self._monitor = None
|
||||
self._stdout_file = ""
|
||||
self._qemu_img_stdout_file = ""
|
||||
self._execute_lock = asyncio.Lock()
|
||||
self._local_udp_tunnels = {}
|
||||
|
||||
@@ -1142,7 +1144,7 @@ class QemuVM(BaseNode):
|
||||
yield from self.add_ubridge_udp_connection("QEMU-{}-{}".format(self._id, adapter_number),
|
||||
self._local_udp_tunnels[adapter_number][1],
|
||||
nio)
|
||||
except IndexError:
|
||||
except (IndexError, KeyError):
|
||||
raise QemuError('Adapter {adapter_number} does not exist on QEMU VM "{name}"'.format(name=self._name,
|
||||
adapter_number=adapter_number))
|
||||
|
||||
@@ -1282,7 +1284,21 @@ class QemuVM(BaseNode):
|
||||
with open(self._stdout_file, "rb") as file:
|
||||
output = file.read().decode("utf-8", errors="replace")
|
||||
except OSError as e:
|
||||
log.warn("Could not read {}: {}".format(self._stdout_file, e))
|
||||
log.warning("Could not read {}: {}".format(self._stdout_file, e))
|
||||
return output
|
||||
|
||||
def read_qemu_img_stdout(self):
|
||||
"""
|
||||
Reads the standard output of the QEMU-IMG process.
|
||||
"""
|
||||
|
||||
output = ""
|
||||
if self._qemu_img_stdout_file:
|
||||
try:
|
||||
with open(self._qemu_img_stdout_file, "rb") as file:
|
||||
output = file.read().decode("utf-8", errors="replace")
|
||||
except OSError as e:
|
||||
log.warning("Could not read {}: {}".format(self._qemu_img_stdout_file, e))
|
||||
return output
|
||||
|
||||
def is_running(self):
|
||||
@@ -1326,8 +1342,14 @@ class QemuVM(BaseNode):
|
||||
def _spice_options(self):
|
||||
|
||||
if self._console:
|
||||
console_host = self._manager.port_manager.console_host
|
||||
if console_host == "0.0.0.0" and socket.has_ipv6:
|
||||
# to fix an issue with Qemu when IPv4 is not enabled
|
||||
# see https://github.com/GNS3/gns3-gui/issues/2352
|
||||
# FIXME: consider making this more global (not just for Qemu + SPICE)
|
||||
console_host = "::"
|
||||
return ["-spice",
|
||||
"addr={},port={},disable-ticketing".format(self._manager.port_manager.console_host, self._console),
|
||||
"addr={},port={},disable-ticketing".format(console_host, self._console),
|
||||
"-vga", "qxl"]
|
||||
else:
|
||||
return []
|
||||
@@ -1360,6 +1382,19 @@ class QemuVM(BaseNode):
|
||||
|
||||
return qemu_img_path
|
||||
|
||||
@asyncio.coroutine
|
||||
def _qemu_img_exec(self, command):
|
||||
|
||||
self._qemu_img_stdout_file = os.path.join(self.working_dir, "qemu-img.log")
|
||||
log.info("logging to {}".format(self._qemu_img_stdout_file))
|
||||
command_string = " ".join(shlex.quote(s) for s in command)
|
||||
log.info("Executing qemu-img with: {}".format(command_string))
|
||||
with open(self._qemu_img_stdout_file, "w", encoding="utf-8") as fd:
|
||||
process = yield from asyncio.create_subprocess_exec(*command, stdout=fd, stderr=subprocess.STDOUT, cwd=self.working_dir)
|
||||
retcode = yield from process.wait()
|
||||
log.info("{} returned with {}".format(self._get_qemu_img(), retcode))
|
||||
return retcode
|
||||
|
||||
@asyncio.coroutine
|
||||
def _disk_options(self):
|
||||
options = []
|
||||
@@ -1381,29 +1416,46 @@ class QemuVM(BaseNode):
|
||||
raise QemuError("{} disk image '{}' linked to '{}' is not accessible".format(disk_name, disk_image, os.path.realpath(disk_image)))
|
||||
else:
|
||||
raise QemuError("{} disk image '{}' is not accessible".format(disk_name, disk_image))
|
||||
else:
|
||||
try:
|
||||
# check for corrupt disk image
|
||||
retcode = yield from self._qemu_img_exec([qemu_img_path, "check", disk_image])
|
||||
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 (yield from 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 (yield from 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)})
|
||||
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))
|
||||
|
||||
if self.linked_clone:
|
||||
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]
|
||||
command_string = " ".join(shlex.quote(s) for s in command)
|
||||
log.info("Executing qemu-img with: {}".format(command_string))
|
||||
process = yield from asyncio.create_subprocess_exec(*command)
|
||||
retcode = yield from process.wait()
|
||||
if retcode is not None and retcode != 0:
|
||||
raise QemuError("Could not create {} disk image: qemu-img returned with {}".format(disk_name,
|
||||
retcode))
|
||||
log.info("{} returned with {}".format(qemu_img_path, retcode))
|
||||
retcode = yield from 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:
|
||||
raise QemuError("Could not create {} disk image: {}".format(disk_name, e))
|
||||
stdout = self.read_qemu_img_stdout()
|
||||
raise QemuError("Could not create '{}' disk image: {}\n{}".format(disk_name, e, stdout))
|
||||
else:
|
||||
# The disk exists we check if the clone work
|
||||
# The disk exists we check if the clone works
|
||||
try:
|
||||
qcow2 = Qcow2(disk)
|
||||
yield from qcow2.rebase(qemu_img_path, disk_image)
|
||||
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
|
||||
@@ -1557,7 +1609,9 @@ class QemuVM(BaseNode):
|
||||
return []
|
||||
if len(os.environ.get("DISPLAY", "")) > 0:
|
||||
return []
|
||||
return ["-nographic"]
|
||||
if "-nographic" not in self._options:
|
||||
return ["-nographic"]
|
||||
return []
|
||||
|
||||
def _run_with_kvm(self, qemu_path, options):
|
||||
"""
|
||||
@@ -1576,7 +1630,10 @@ class QemuVM(BaseNode):
|
||||
return False
|
||||
|
||||
if not os.path.exists("/dev/kvm"):
|
||||
raise QemuError("KVM acceleration cannot be used (/dev/kvm doesn't exist). You can turn off KVM support in the gns3_server.conf by adding enable_kvm = false to the [Qemu] section.")
|
||||
if self.manager.config.get_section_config("Qemu").getboolean("require_kvm", True):
|
||||
raise QemuError("KVM acceleration cannot be used (/dev/kvm doesn't exist). You can turn off KVM support in the gns3_server.conf by adding enable_kvm = false to the [Qemu] section.")
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -1588,6 +1645,10 @@ class QemuVM(BaseNode):
|
||||
"""
|
||||
|
||||
additional_options = self._options.strip()
|
||||
additional_options = additional_options.replace("%vm-name%", '"' + self._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('"', '\\"') + '"')
|
||||
command = [self.qemu_path]
|
||||
command.extend(["-name", self._name])
|
||||
command.extend(["-m", "{}M".format(self._ram)])
|
||||
|
||||
@@ -846,10 +846,8 @@ class VirtualBoxVM(BaseNode):
|
||||
nio = self._local_udp_tunnels[adapter_number][0]
|
||||
|
||||
if nio:
|
||||
if not self._use_any_adapter and attachment not in ("none", "null", "generic"):
|
||||
raise VirtualBoxError("Attachment ({}) already configured on adapter {}. "
|
||||
"Please set it to 'Not attached' to allow GNS3 to use it.".format(attachment,
|
||||
adapter_number + 1))
|
||||
if not self._use_any_adapter and attachment in ("nat", "bridged", "intnet", "hostonly", "natnetwork"):
|
||||
continue
|
||||
|
||||
yield from self._modify_vm("--nictrace{} off".format(adapter_number + 1))
|
||||
vbox_adapter_type = "82540EM"
|
||||
@@ -972,23 +970,40 @@ class VirtualBoxVM(BaseNode):
|
||||
raise VirtualBoxError("Adapter {adapter_number} doesn't exist on VirtualBox VM '{name}'".format(name=self.name,
|
||||
adapter_number=adapter_number))
|
||||
|
||||
# check if trying to connect to a nat, bridged, host-only or any other special adapter
|
||||
nic_attachments = yield from self._get_nic_attachements(self._maximum_adapters)
|
||||
attachment = nic_attachments[adapter_number]
|
||||
if attachment in ("nat", "bridged", "intnet", "hostonly", "natnetwork"):
|
||||
if not self._use_any_adapter:
|
||||
raise VirtualBoxError("Attachment '{attachment}' is already configured on adapter {adapter_number}. "
|
||||
"Please remove it or allow VirtualBox VM '{name}' to use any adapter.".format(attachment=attachment,
|
||||
adapter_number=adapter_number,
|
||||
name=self.name))
|
||||
elif self.is_running():
|
||||
# dynamically configure an UDP tunnel attachment if the VM is already running
|
||||
local_nio = self._local_udp_tunnels[adapter_number][0]
|
||||
if local_nio and isinstance(local_nio, NIOUDP):
|
||||
yield from self._control_vm("nic{} generic UDPTunnel".format(adapter_number + 1))
|
||||
yield from self._control_vm("nicproperty{} sport={}".format(adapter_number + 1, local_nio.lport))
|
||||
yield from self._control_vm("nicproperty{} dest={}".format(adapter_number + 1, local_nio.rhost))
|
||||
yield from self._control_vm("nicproperty{} dport={}".format(adapter_number + 1, local_nio.rport))
|
||||
yield from self._control_vm("setlinkstate{} on".format(adapter_number + 1))
|
||||
|
||||
if self.is_running():
|
||||
try:
|
||||
yield from self.add_ubridge_udp_connection("VBOX-{}-{}".format(self._id, adapter_number),
|
||||
self._local_udp_tunnels[adapter_number][1],
|
||||
nio)
|
||||
except KeyError:
|
||||
raise VirtualBoxError("Adapter {adapter_number} doesn't exist on VirtualBox VM '{name}'".format(
|
||||
name=self.name,
|
||||
adapter_number=adapter_number))
|
||||
raise VirtualBoxError("Adapter {adapter_number} doesn't exist on VirtualBox VM '{name}'".format(name=self.name,
|
||||
adapter_number=adapter_number))
|
||||
yield from self._control_vm("setlinkstate{} on".format(adapter_number + 1))
|
||||
|
||||
adapter.add_nio(0, nio)
|
||||
log.info("VirtualBox VM '{name}' [{id}]: {nio} added to adapter {adapter_number}".format(
|
||||
name=self.name,
|
||||
id=self.id,
|
||||
nio=nio,
|
||||
adapter_number=adapter_number))
|
||||
log.info("VirtualBox VM '{name}' [{id}]: {nio} added to adapter {adapter_number}".format(name=self.name,
|
||||
id=self.id,
|
||||
nio=nio,
|
||||
adapter_number=adapter_number))
|
||||
|
||||
@asyncio.coroutine
|
||||
def adapter_update_nio_binding(self, adapter_number, nio):
|
||||
|
||||
@@ -736,13 +736,20 @@ class VMwareVM(BaseNode):
|
||||
|
||||
self._read_vmx_file()
|
||||
# check if trying to connect to a nat, bridged or host-only adapter
|
||||
if not self._use_any_adapter and self._get_vmx_setting("ethernet{}.present".format(adapter_number), "TRUE"):
|
||||
if self._get_vmx_setting("ethernet{}.present".format(adapter_number), "TRUE"):
|
||||
# check for the connection type
|
||||
connection_type = "ethernet{}.connectiontype".format(adapter_number)
|
||||
if connection_type in self._vmx_pairs and self._vmx_pairs[connection_type] in ("nat", "bridged", "hostonly"):
|
||||
raise VMwareError("Attachment ({}) already configured on network adapter {}. "
|
||||
"Please remove it or allow GNS3 to use any adapter.".format(self._vmx_pairs[connection_type],
|
||||
adapter_number))
|
||||
if not self._use_any_adapter:
|
||||
raise VMwareError("Attachment '{attachment}' is already configured on network adapter {adapter_number}. "
|
||||
"Please remove it or allow VMware VM '{name}' to use any adapter.".format(attachment=self._vmx_pairs[connection_type],
|
||||
adapter_number=adapter_number,
|
||||
name=self.name))
|
||||
elif 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,
|
||||
name=self.name))
|
||||
|
||||
adapter.add_nio(0, nio)
|
||||
if self._started and self._ubridge_hypervisor:
|
||||
|
||||
@@ -587,7 +587,7 @@ class Controller:
|
||||
@property
|
||||
def projects(self):
|
||||
"""
|
||||
:returns: The dictionary of computes managed by GNS3
|
||||
:returns: The dictionary of projects managed by GNS3
|
||||
"""
|
||||
return self._projects
|
||||
|
||||
@@ -622,13 +622,14 @@ class Controller:
|
||||
return Controller._instance
|
||||
|
||||
@asyncio.coroutine
|
||||
def autoidlepc(self, compute_id, platform, image):
|
||||
def autoidlepc(self, compute_id, platform, image, ram):
|
||||
"""
|
||||
Compute and IDLE PC value for an image
|
||||
|
||||
:param compute_id: ID of the compute where the idlepc operation need to run
|
||||
:param platform: Platform type
|
||||
:param image: Image to use
|
||||
:param ram: amount of RAM to use
|
||||
"""
|
||||
compute = self.get_compute(compute_id)
|
||||
for project in list(self._projects.values()):
|
||||
@@ -636,7 +637,7 @@ class Controller:
|
||||
yield from project.delete()
|
||||
self.remove_project(project)
|
||||
project = yield from self.add_project(name="AUTOIDLEPC")
|
||||
node = yield from project.add_node(compute, "AUTOIDLEPC", str(uuid.uuid4()), node_type="dynamips", platform=platform, image=image, ram=512)
|
||||
node = yield from project.add_node(compute, "AUTOIDLEPC", str(uuid.uuid4()), node_type="dynamips", platform=platform, image=image, ram=ram)
|
||||
res = yield from node.dynamips_auto_idlepc()
|
||||
yield from project.delete()
|
||||
self.remove_project(project)
|
||||
|
||||
@@ -320,6 +320,22 @@ class Compute:
|
||||
raise aiohttp.web.HTTPNotFound(text="{} not found on compute".format(path))
|
||||
return response
|
||||
|
||||
@asyncio.coroutine
|
||||
def download_image(self, image_type, image):
|
||||
"""
|
||||
Read file of a project and download it
|
||||
|
||||
:param image_type: Image type
|
||||
:param image: The path of the image
|
||||
:returns: A file stream
|
||||
"""
|
||||
|
||||
url = self._getUrl("/{}/images/{}".format(image_type, image))
|
||||
response = yield from self._session().request("GET", url, auth=self._auth)
|
||||
if response.status == 404:
|
||||
raise aiohttp.web.HTTPNotFound(text="{} not found on compute".format(image))
|
||||
return response
|
||||
|
||||
@asyncio.coroutine
|
||||
def stream_file(self, project, path):
|
||||
"""
|
||||
@@ -506,10 +522,16 @@ class Compute:
|
||||
else:
|
||||
data = json.dumps(data).encode("utf-8")
|
||||
try:
|
||||
log.debug("Attempting request to compute: {method} {url} {headers}".format(
|
||||
method=method,
|
||||
url=url,
|
||||
headers=headers
|
||||
))
|
||||
response = yield from self._session().request(method, url, headers=headers, data=data, auth=self._auth, chunked=chunked, timeout=timeout)
|
||||
except asyncio.TimeoutError as e:
|
||||
raise ComputeError("Timeout error when connecting to {}".format(url))
|
||||
except (aiohttp.ClientError, aiohttp.ServerDisconnectedError, ValueError, KeyError) as e:
|
||||
except (aiohttp.ClientError, aiohttp.ServerDisconnectedError, ValueError, KeyError, socket.gaierror) as e:
|
||||
# aiohttp 2.3.1 raises socket.gaierror when cannot find host
|
||||
raise ComputeError(str(e))
|
||||
body = yield from response.read()
|
||||
if body and not raw:
|
||||
|
||||
@@ -58,7 +58,8 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id
|
||||
# First we process the .gns3 in order to be sure we don't have an error
|
||||
for file in os.listdir(project._path):
|
||||
if file.endswith(".gns3"):
|
||||
_export_project_file(project, os.path.join(project._path, file), z, include_images, keep_compute_id, allow_all_nodes)
|
||||
images = yield from _export_project_file(project, os.path.join(project._path, file),
|
||||
z, include_images, keep_compute_id, allow_all_nodes, temporary_dir)
|
||||
|
||||
for root, dirs, files in os.walk(project._path, topdown=True):
|
||||
files = [f for f in files if not _filter_files(os.path.join(root, f))]
|
||||
@@ -78,6 +79,8 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id
|
||||
else:
|
||||
z.write(path, os.path.relpath(path, project._path), compress_type=zipfile.ZIP_DEFLATED)
|
||||
|
||||
downloaded_files = set()
|
||||
|
||||
for compute in project.computes:
|
||||
if compute.id != "local":
|
||||
compute_files = yield from compute.list_files(project)
|
||||
@@ -94,6 +97,8 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id
|
||||
response.close()
|
||||
f.close()
|
||||
z.write(temp_path, arcname=compute_file["path"], compress_type=zipfile.ZIP_DEFLATED)
|
||||
downloaded_files.add(compute_file['path'])
|
||||
|
||||
return z
|
||||
|
||||
|
||||
@@ -121,7 +126,8 @@ def _filter_files(path):
|
||||
return False
|
||||
|
||||
|
||||
def _export_project_file(project, path, z, include_images, keep_compute_id, allow_all_nodes):
|
||||
@asyncio.coroutine
|
||||
def _export_project_file(project, path, z, include_images, keep_compute_id, allow_all_nodes, temporary_dir):
|
||||
"""
|
||||
Take a project file (.gns3) and patch it for the export
|
||||
|
||||
@@ -131,7 +137,7 @@ def _export_project_file(project, path, z, include_images, keep_compute_id, allo
|
||||
"""
|
||||
|
||||
# Image file that we need to include in the exported archive
|
||||
images = set()
|
||||
images = []
|
||||
|
||||
with open(path) as f:
|
||||
topology = json.load(f)
|
||||
@@ -139,6 +145,8 @@ def _export_project_file(project, path, z, include_images, keep_compute_id, allo
|
||||
if "topology" in topology:
|
||||
if "nodes" in topology["topology"]:
|
||||
for node in topology["topology"]["nodes"]:
|
||||
compute_id = node.get('compute_id', 'local')
|
||||
|
||||
if node["node_type"] == "virtualbox" and node.get("properties", {}).get("linked_clone"):
|
||||
raise aiohttp.web.HTTPConflict(text="Topology with a linked {} clone could not be exported. Use qemu instead.".format(node["node_type"]))
|
||||
if not allow_all_nodes and node["node_type"] in ["virtualbox", "vmware", "cloud"]:
|
||||
@@ -149,22 +157,42 @@ def _export_project_file(project, path, z, include_images, keep_compute_id, allo
|
||||
|
||||
if "properties" in node and node["node_type"] != "docker":
|
||||
for prop, value in node["properties"].items():
|
||||
if prop.endswith("image"):
|
||||
if not keep_compute_id: # If we keep the original compute we can keep the image path
|
||||
node["properties"][prop] = os.path.basename(value)
|
||||
if include_images is True:
|
||||
images.add(value)
|
||||
if not prop.endswith("image"):
|
||||
continue
|
||||
|
||||
if value is None or value.strip() == '':
|
||||
continue
|
||||
|
||||
if not keep_compute_id: # If we keep the original compute we can keep the image path
|
||||
node["properties"][prop] = os.path.basename(value)
|
||||
|
||||
if include_images is True:
|
||||
images.append({
|
||||
'compute_id': compute_id,
|
||||
'image': value,
|
||||
'image_type': node['node_type']
|
||||
})
|
||||
|
||||
if not keep_compute_id:
|
||||
topology["topology"]["computes"] = [] # Strip compute informations because could contain secret info like password
|
||||
topology["topology"]["computes"] = [] # Strip compute information because could contain secret info like password
|
||||
|
||||
for image in images:
|
||||
_export_images(project, image, z)
|
||||
local_images = set([i['image'] for i in images if i['compute_id'] == 'local'])
|
||||
|
||||
for image in local_images:
|
||||
_export_local_images(project, image, z)
|
||||
|
||||
remote_images = set([
|
||||
(i['compute_id'], i['image_type'], i['image'])
|
||||
for i in images if i['compute_id'] != 'local'])
|
||||
|
||||
for compute_id, image_type, image in remote_images:
|
||||
yield from _export_remote_images(project, compute_id, image_type, image, z, temporary_dir)
|
||||
|
||||
z.writestr("project.gns3", json.dumps(topology).encode())
|
||||
|
||||
return images
|
||||
|
||||
def _export_images(project, image, z):
|
||||
def _export_local_images(project, image, z):
|
||||
"""
|
||||
Take a project file (.gns3) and export images to the zip
|
||||
|
||||
@@ -191,4 +219,45 @@ def _export_images(project, image, z):
|
||||
arcname = os.path.join("images", directory, os.path.basename(image))
|
||||
z.write(path, arcname)
|
||||
return
|
||||
raise aiohttp.web.HTTPConflict(text="Topology could not be exported because the image {} is not available. If you use multiple server, we need a copy of the image on the main server.".format(image))
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def _export_remote_images(project, compute_id, image_type, image, project_zipfile, temporary_dir):
|
||||
"""
|
||||
Export specific image from remote compute
|
||||
:param project:
|
||||
:param compute_id:
|
||||
:param image_type:
|
||||
:param image:
|
||||
:param project_zipfile:
|
||||
:return:
|
||||
"""
|
||||
|
||||
log.info("Obtaining image `{}` from `{}`".format(image, compute_id))
|
||||
|
||||
try:
|
||||
compute = [compute for compute in project.computes if compute.id == compute_id][0]
|
||||
except IndexError:
|
||||
raise aiohttp.web.HTTPConflict(
|
||||
text="Cannot export image from `{}` compute. Compute doesn't exist.".format(compute_id))
|
||||
|
||||
(fd, temp_path) = tempfile.mkstemp(dir=temporary_dir)
|
||||
f = open(fd, "wb", closefd=True)
|
||||
response = yield from compute.download_image(image_type, image)
|
||||
|
||||
if response.status != 200:
|
||||
raise aiohttp.web.HTTPConflict(
|
||||
text="Cannot export image from `{}` compute. Compute sent `{}` status.".format(
|
||||
compute_id, response.status))
|
||||
|
||||
while True:
|
||||
data = yield from response.content.read(512)
|
||||
if not data:
|
||||
break
|
||||
f.write(data)
|
||||
response.close()
|
||||
f.close()
|
||||
arcname = os.path.join("images", image_type, image)
|
||||
log.info("Saved {}".format(arcname))
|
||||
project_zipfile.write(temp_path, arcname=arcname, compress_type=zipfile.ZIP_DEFLATED)
|
||||
|
||||
@@ -19,6 +19,7 @@ import sys
|
||||
import copy
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import ipaddress
|
||||
|
||||
from ...utils.asyncio import locked_coroutine
|
||||
from .vmware_gns3_vm import VMwareGNS3VM
|
||||
@@ -296,6 +297,37 @@ class GNS3VM:
|
||||
user=self.user,
|
||||
password=self.password)
|
||||
|
||||
yield from self._check_network(compute)
|
||||
|
||||
@asyncio.coroutine
|
||||
def _check_network(self, compute):
|
||||
"""
|
||||
Check that the VM is in the same subnet as the local server
|
||||
"""
|
||||
|
||||
vm_interfaces = yield from compute.interfaces()
|
||||
vm_interface_netmask = None
|
||||
for interface in vm_interfaces:
|
||||
if interface["ip_address"] == self.ip_address:
|
||||
vm_interface_netmask = interface["netmask"]
|
||||
break
|
||||
if vm_interface_netmask:
|
||||
vm_network = ipaddress.ip_interface("{}/{}".format(compute.host_ip, vm_interface_netmask)).network
|
||||
for compute_id in self._controller.computes:
|
||||
if compute_id == "local":
|
||||
compute = self._controller.get_compute(compute_id)
|
||||
interfaces = yield from compute.interfaces()
|
||||
netmask = None
|
||||
for interface in interfaces:
|
||||
if interface["ip_address"] == compute.host_ip:
|
||||
netmask = interface["netmask"]
|
||||
break
|
||||
if netmask:
|
||||
compute_network = ipaddress.ip_interface("{}/{}".format(compute.host_ip, netmask)).network
|
||||
if vm_network.compare_networks(compute_network) != 0:
|
||||
msg = "The GNS3 VM ({}) is not on the same network as the {} server ({}), please make sure the local server binding is in the same network as the GNS3 VM".format(vm_network, compute_id, compute_network)
|
||||
self._controller.notification.emit("log.warning", {"message": msg})
|
||||
|
||||
@locked_coroutine
|
||||
def _suspend(self):
|
||||
"""
|
||||
|
||||
@@ -300,9 +300,12 @@ class Link:
|
||||
try:
|
||||
stream_content = yield from self.read_pcap_from_source()
|
||||
except aiohttp.web.HTTPException as e:
|
||||
log.error("Could not stream pcap file: error {}: {}".format(e.status, e.text))
|
||||
error_msg = "Could not stream PCAP file: error {}: {}".format(e.status, e.text)
|
||||
log.error(error_msg)
|
||||
self._capturing = False
|
||||
self._project.notification.emit("log.error", {"message": error_msg})
|
||||
self._project.controller.notification.emit("link.updated", self.__json__())
|
||||
|
||||
with stream_content as stream:
|
||||
with open(self.capture_file_path, "wb+") as f:
|
||||
while self._capturing:
|
||||
|
||||
@@ -325,7 +325,7 @@ class Node:
|
||||
if self._node_type == "docker":
|
||||
timeout = None
|
||||
else:
|
||||
timeout = 120
|
||||
timeout = 1200
|
||||
trial = 0
|
||||
while trial != 6:
|
||||
try:
|
||||
|
||||
@@ -474,7 +474,7 @@ class Project:
|
||||
"""
|
||||
for link in list(self._links.values()):
|
||||
if node in link.nodes:
|
||||
yield from self.delete_link(link.id)
|
||||
yield from self.delete_link(link.id, force_delete=True)
|
||||
|
||||
@open_required
|
||||
@asyncio.coroutine
|
||||
@@ -565,10 +565,14 @@ class Project:
|
||||
|
||||
@open_required
|
||||
@asyncio.coroutine
|
||||
def delete_link(self, link_id):
|
||||
def delete_link(self, link_id, force_delete=False):
|
||||
link = self.get_link(link_id)
|
||||
del self._links[link.id]
|
||||
yield from link.delete()
|
||||
try:
|
||||
yield from link.delete()
|
||||
except Exception:
|
||||
if force_delete is False:
|
||||
raise
|
||||
self.dump()
|
||||
self.controller.notification.emit("link.deleted", link.__json__())
|
||||
|
||||
@@ -789,7 +793,7 @@ class Project:
|
||||
yield from link.add_node(node, node_link["adapter_number"], node_link["port_number"], label=node_link.get("label"), dump=False)
|
||||
if len(link.nodes) != 2:
|
||||
# a link should have 2 attached nodes, this can happen with corrupted projects
|
||||
yield from self.delete_link(link.id)
|
||||
yield from self.delete_link(link.id, force_delete=True)
|
||||
for drawing_data in topology.get("drawings", []):
|
||||
yield from self.add_drawing(dump=False, **drawing_data)
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class CrashReport:
|
||||
Report crash to a third party service
|
||||
"""
|
||||
|
||||
DSN = "sync+https://6ea2fd77178749dea96d725eb4b1b4d1:307d5441e2d7405fa0bd668042392b02@sentry.io/38482"
|
||||
DSN = "sync+https://ad494b2c01ee40a5b0250d950c815bd2:547cc717c79e4893b5950f6bd835af98@sentry.io/38482"
|
||||
if hasattr(sys, "frozen"):
|
||||
cacert = get_resource("cacert.pem")
|
||||
if cacert is not None and os.path.isfile(cacert):
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
import aiohttp
|
||||
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.schemas.nio import NIO_SCHEMA
|
||||
@@ -448,6 +449,28 @@ class DynamipsVMHandler:
|
||||
yield from dynamips_manager.write_image(request.match_info["filename"], request.content)
|
||||
response.set_status(204)
|
||||
|
||||
@Route.get(
|
||||
r"/dynamips/images/{filename:.+}",
|
||||
parameters={
|
||||
"filename": "Image filename"
|
||||
},
|
||||
status_codes={
|
||||
200: "Image returned",
|
||||
},
|
||||
raw=True,
|
||||
description="Download a Dynamips IOS image")
|
||||
def download_image(request, response):
|
||||
filename = request.match_info["filename"]
|
||||
|
||||
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()
|
||||
|
||||
yield from response.file(image_path)
|
||||
|
||||
@Route.post(
|
||||
r"/projects/{project_id}/dynamips/nodes/{node_id}/duplicate",
|
||||
parameters={
|
||||
@@ -467,3 +490,4 @@ class DynamipsVMHandler:
|
||||
)
|
||||
response.set_status(201)
|
||||
response.json(new_node)
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
from aiohttp.web import HTTPConflict
|
||||
|
||||
import aiohttp.web
|
||||
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.schemas.nio import NIO_SCHEMA
|
||||
@@ -59,6 +60,7 @@ class IOUHandler:
|
||||
vm = yield from iou.create_node(request.json.pop("name"),
|
||||
request.match_info["project_id"],
|
||||
request.json.get("node_id"),
|
||||
path=request.json.get("path"),
|
||||
console=request.json.get("console"))
|
||||
|
||||
for name, value in request.json.items():
|
||||
@@ -67,6 +69,8 @@ class IOUHandler:
|
||||
continue
|
||||
if name == "private_config_content" and (vm.private_config_content and len(vm.private_config_content) > 0):
|
||||
continue
|
||||
if request.json.get("use_default_iou_values") and (name == "ram" or name == "nvram"):
|
||||
continue
|
||||
setattr(vm, name, value)
|
||||
response.set_status(201)
|
||||
response.json(vm)
|
||||
@@ -113,6 +117,11 @@ class IOUHandler:
|
||||
for name, value in request.json.items():
|
||||
if hasattr(vm, name) and getattr(vm, name) != value:
|
||||
setattr(vm, name, value)
|
||||
|
||||
if vm.use_default_iou_values:
|
||||
# update the default IOU values in case the image or use_default_iou_values have changed
|
||||
# this is important to have the correct NVRAM amount in order to correctly push the configs to the NVRAM
|
||||
yield from vm.update_default_iou_values()
|
||||
vm.updated()
|
||||
response.json(vm)
|
||||
|
||||
@@ -239,7 +248,7 @@ class IOUHandler:
|
||||
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
nio_type = request.json["type"]
|
||||
if nio_type not in ("nio_udp", "nio_tap", "nio_ethernet", "nio_generic_ethernet"):
|
||||
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
|
||||
raise aiohttp.web.HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
|
||||
nio = iou_manager.create_nio(request.json)
|
||||
yield from vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), int(request.match_info["port_number"]), nio)
|
||||
response.set_status(201)
|
||||
@@ -378,3 +387,26 @@ class IOUHandler:
|
||||
iou_manager = IOU.instance()
|
||||
yield from iou_manager.write_image(request.match_info["filename"], request.content)
|
||||
response.set_status(204)
|
||||
|
||||
|
||||
@Route.get(
|
||||
r"/iou/images/{filename:.+}",
|
||||
parameters={
|
||||
"filename": "Image filename"
|
||||
},
|
||||
status_codes={
|
||||
200: "Image returned",
|
||||
},
|
||||
raw=True,
|
||||
description="Download an IOU image")
|
||||
def download_image(request, response):
|
||||
filename = request.match_info["filename"]
|
||||
|
||||
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()
|
||||
|
||||
yield from response.file(image_path)
|
||||
@@ -231,7 +231,7 @@ class ProjectHandler:
|
||||
|
||||
# Raise error if user try to escape
|
||||
if path[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
path = os.path.join(project.path, path)
|
||||
|
||||
response.content_type = "application/octet-stream"
|
||||
@@ -272,7 +272,7 @@ class ProjectHandler:
|
||||
|
||||
# Raise an error if user try to escape
|
||||
if path[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
path = os.path.join(project.path, path)
|
||||
|
||||
response.content_type = "application/octet-stream"
|
||||
@@ -314,7 +314,7 @@ class ProjectHandler:
|
||||
|
||||
# Raise error if user try to escape
|
||||
if path[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
path = os.path.join(project.path, path)
|
||||
|
||||
response.set_status(200)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
import sys
|
||||
import os.path
|
||||
|
||||
from aiohttp.web import HTTPConflict
|
||||
import aiohttp.web
|
||||
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.compute.project_manager import ProjectManager
|
||||
@@ -183,7 +183,7 @@ class QEMUHandler:
|
||||
if sys.platform.startswith("linux") and qemu_manager.config.get_section_config("Qemu").getboolean("enable_kvm", True) and "-no-kvm" not in vm.options:
|
||||
pm = ProjectManager.instance()
|
||||
if pm.check_hardware_virtualization(vm) is False:
|
||||
raise HTTPConflict(text="Cannot start VM with KVM enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
|
||||
raise aiohttp.web.HTTPConflict(text="Cannot start VM with KVM enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
|
||||
yield from vm.start()
|
||||
response.json(vm)
|
||||
|
||||
@@ -285,7 +285,7 @@ class QEMUHandler:
|
||||
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
nio_type = request.json["type"]
|
||||
if nio_type not in ("nio_udp", "nio_tap", "nio_nat"):
|
||||
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
|
||||
raise aiohttp.web.HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
|
||||
nio = qemu_manager.create_nio(request.json)
|
||||
yield from vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio)
|
||||
response.set_status(201)
|
||||
@@ -479,3 +479,25 @@ class QEMUHandler:
|
||||
qemu_manager = Qemu.instance()
|
||||
yield from qemu_manager.write_image(request.match_info["filename"], request.content)
|
||||
response.set_status(204)
|
||||
|
||||
@Route.get(
|
||||
r"/qemu/images/{filename:.+}",
|
||||
parameters={
|
||||
"filename": "Image filename"
|
||||
},
|
||||
status_codes={
|
||||
200: "Image returned",
|
||||
},
|
||||
raw=True,
|
||||
description="Download Qemu image")
|
||||
def download_image(request, response):
|
||||
filename = request.match_info["filename"]
|
||||
|
||||
iou_manager = Qemu.instance()
|
||||
image_path = iou_manager.get_abs_image_path(filename)
|
||||
|
||||
# Raise error if user try to escape
|
||||
if filename[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
yield from response.file(image_path)
|
||||
@@ -185,7 +185,7 @@ class ComputeHandler:
|
||||
response.set_status(204)
|
||||
|
||||
@Route.post(
|
||||
r"/computes/{compute_id}/autoidlepc",
|
||||
r"/computes/{compute_id}/auto_idlepc",
|
||||
parameters={
|
||||
"compute_id": "Compute UUID"
|
||||
},
|
||||
@@ -195,6 +195,6 @@ class ComputeHandler:
|
||||
description="Compute IDLE PC value")
|
||||
def autoidlepc(request, response):
|
||||
controller = Controller.instance()
|
||||
res = yield from controller.autoidlepc(request.match_info["compute_id"], request.json["platform"], request.json["image"])
|
||||
response.set_status(200)
|
||||
res = yield from controller.autoidlepc(request.match_info["compute_id"], request.json["platform"], request.json["image"], request.json["ram"])
|
||||
response.json(res)
|
||||
response.set_status(200)
|
||||
@@ -15,7 +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 os
|
||||
import aiohttp
|
||||
|
||||
from gns3server.web.route import Route
|
||||
@@ -370,7 +369,7 @@ class NodeHandler:
|
||||
|
||||
# Raise error if user try to escape
|
||||
if path[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
node_type = node.node_type
|
||||
path = "/project-files/{}/{}/{}".format(node_type, node.id, path)
|
||||
@@ -406,7 +405,7 @@ class NodeHandler:
|
||||
|
||||
# Raise error if user try to escape
|
||||
if path[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
node_type = node.node_type
|
||||
path = "/project-files/{}/{}/{}".format(node_type, node.id, path)
|
||||
|
||||
@@ -398,7 +398,7 @@ class ProjectHandler:
|
||||
|
||||
# Raise error if user try to escape
|
||||
if path[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
path = os.path.join(project.path, path)
|
||||
|
||||
response.content_type = "application/octet-stream"
|
||||
@@ -440,7 +440,7 @@ class ProjectHandler:
|
||||
|
||||
# Raise error if user try to escape
|
||||
if path[0] == ".":
|
||||
raise aiohttp.web.HTTPForbidden
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
path = os.path.join(project.path, path)
|
||||
|
||||
response.set_status(200)
|
||||
|
||||
@@ -209,6 +209,12 @@ class AsyncioTelnetServer:
|
||||
yield from connection.disconnected()
|
||||
del self._connections[network_writer]
|
||||
|
||||
@asyncio.coroutine
|
||||
def close(self):
|
||||
for writer, connection in self._connections.items():
|
||||
writer.write_eof()
|
||||
yield from writer.drain()
|
||||
|
||||
@asyncio.coroutine
|
||||
def client_connected_hook(self):
|
||||
pass
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
# or negative for a release candidate or beta (after the base version
|
||||
# number has been incremented)
|
||||
|
||||
__version__ = "2.1.0"
|
||||
__version_info__ = (2, 1, 0, 0)
|
||||
__version__ = "2.1.1"
|
||||
__version_info__ = (2, 1, 1, 0)
|
||||
|
||||
# If it's a git checkout try to add the commit
|
||||
if "dev" in __version__:
|
||||
|
||||
+23
-16
@@ -113,7 +113,7 @@ class Response(aiohttp.web.Response):
|
||||
self.body = json.dumps(answer, indent=4, sort_keys=True).encode('utf-8')
|
||||
|
||||
@asyncio.coroutine
|
||||
def file(self, path):
|
||||
def file(self, path, status=200, set_content_length=True):
|
||||
"""
|
||||
Return a file as a response
|
||||
"""
|
||||
@@ -124,27 +124,34 @@ class Response(aiohttp.web.Response):
|
||||
self.headers[aiohttp.hdrs.CONTENT_ENCODING] = encoding
|
||||
self.content_type = ct
|
||||
|
||||
st = os.stat(path)
|
||||
self.last_modified = st.st_mtime
|
||||
self.headers[aiohttp.hdrs.CONTENT_LENGTH] = str(st.st_size)
|
||||
if set_content_length:
|
||||
st = os.stat(path)
|
||||
self.last_modified = st.st_mtime
|
||||
self.headers[aiohttp.hdrs.CONTENT_LENGTH] = str(st.st_size)
|
||||
else:
|
||||
self.enable_chunked_encoding()
|
||||
|
||||
with open(path, 'rb') as fobj:
|
||||
yield from self.prepare(self._request)
|
||||
chunk_size = 4096
|
||||
chunk = fobj.read(chunk_size)
|
||||
while chunk:
|
||||
self.write(chunk)
|
||||
yield from self.drain()
|
||||
chunk = fobj.read(chunk_size)
|
||||
self.set_status(status)
|
||||
|
||||
if chunk:
|
||||
self.write(chunk[:count])
|
||||
yield from self.drain()
|
||||
try:
|
||||
with open(path, 'rb') as fobj:
|
||||
yield from self.prepare(self._request)
|
||||
|
||||
while True:
|
||||
data = fobj.read(4096)
|
||||
if not data:
|
||||
break
|
||||
yield from self.write(data)
|
||||
yield from self.drain()
|
||||
|
||||
except FileNotFoundError:
|
||||
raise aiohttp.web.HTTPNotFound()
|
||||
except PermissionError:
|
||||
raise aiohttp.web.HTTPForbidden()
|
||||
|
||||
def redirect(self, url):
|
||||
"""
|
||||
Redirect to url
|
||||
|
||||
:params url: Redirection URL
|
||||
"""
|
||||
raise aiohttp.web.HTTPFound(url)
|
||||
@@ -42,8 +42,8 @@ import gns3server.handlers
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
if not aiohttp.__version__.startswith("2.2"):
|
||||
raise RuntimeError("aiohttp 2.2 is required to run the GNS3 server")
|
||||
if not (aiohttp.__version__.startswith("2.2") or aiohttp.__version__.startswith("2.3")):
|
||||
raise RuntimeError("aiohttp 2.2.x or 2.3.x is required to run the GNS3 server")
|
||||
|
||||
|
||||
class WebServer:
|
||||
@@ -101,7 +101,12 @@ class WebServer:
|
||||
if self._app:
|
||||
yield from self._app.shutdown()
|
||||
if self._handler:
|
||||
yield from self._handler.finish_connections(2) # Parameter is timeout
|
||||
try:
|
||||
# aiohttp < 2.3
|
||||
yield from self._handler.finish_connections(2) # Parameter is timeout
|
||||
except AttributeError:
|
||||
# aiohttp >= 2.3
|
||||
yield from self._handler.shutdown(2) # Parameter is timeout
|
||||
if self._app:
|
||||
yield from self._app.cleanup()
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
jsonschema>=2.4.0
|
||||
aiohttp>=2.2.0,<2.3.0 # pyup: ignore
|
||||
aiohttp>=2.2.0,<2.4.0 # pyup: ignore
|
||||
aiohttp-cors>=0.5.3,<0.6.0 # pyup: ignore
|
||||
yarl>=0.11,<0.12 # pyup: ignore
|
||||
Jinja2>=2.7.3
|
||||
|
||||
@@ -212,6 +212,7 @@ report_errors = True
|
||||
|
||||
[Qemu]
|
||||
enable_kvm = True
|
||||
require_kvm = True
|
||||
EOFC
|
||||
|
||||
chown -R gns3:gns3 /etc/gns3
|
||||
@@ -298,6 +299,7 @@ report_errors = True
|
||||
|
||||
[Qemu]
|
||||
enable_kvm = True
|
||||
require_kvm = True
|
||||
EOFSERVER
|
||||
|
||||
log "Install packages for Open VPN"
|
||||
|
||||
@@ -769,6 +769,8 @@ def test_adapter_add_nio_binding(vm, loop):
|
||||
|
||||
|
||||
def test_adapter_udpate_nio_binding(vm, loop):
|
||||
vm.ubridge = MagicMock()
|
||||
vm.ubridge.is_running.return_value = True
|
||||
vm._ubridge_apply_filters = AsyncioMagicMock()
|
||||
vm._bridges = set(('bridge0', ))
|
||||
nio = {"type": "nio_udp",
|
||||
|
||||
@@ -229,7 +229,7 @@ def test_list_images(loop, qemu, tmpdir):
|
||||
f.write("1")
|
||||
|
||||
with patch("gns3server.utils.images.default_images_directory", return_value=str(tmpdir)):
|
||||
assert loop.run_until_complete(qemu.list_images()) == [
|
||||
assert sorted(loop.run_until_complete(qemu.list_images()), key=lambda k: k['filename']) == [
|
||||
{"filename": "a.qcow2", "path": "a.qcow2", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1},
|
||||
{"filename": "b.qcow2", "path": "b.qcow2", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1}
|
||||
]
|
||||
@@ -249,7 +249,7 @@ def test_list_images_recursives(loop, qemu, tmpdir):
|
||||
|
||||
with patch("gns3server.utils.images.default_images_directory", return_value=str(tmpdir)):
|
||||
|
||||
assert loop.run_until_complete(qemu.list_images()) == [
|
||||
assert sorted(loop.run_until_complete(qemu.list_images()), key=lambda k: k['filename']) == [
|
||||
{"filename": "a.qcow2", "path": "a.qcow2", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1},
|
||||
{"filename": "b.qcow2", "path": "b.qcow2", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1},
|
||||
{"filename": "c.qcow2", "path": force_unix_path(os.path.sep.join(["c", "c.qcow2"])), "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1}
|
||||
|
||||
@@ -388,9 +388,10 @@ def test_start_vm(controller, async_run):
|
||||
"vmname": "GNS3 VM"
|
||||
}
|
||||
with asyncio_patch("gns3server.controller.gns3vm.vmware_gns3_vm.VMwareGNS3VM.start") as mock:
|
||||
with asyncio_patch("gns3server.controller.compute.Compute.connect") as mock_connect:
|
||||
async_run(controller.start())
|
||||
assert mock.called
|
||||
with asyncio_patch("gns3server.controller.gns3vm.GNS3VM._check_network") as mock_check_network:
|
||||
with asyncio_patch("gns3server.controller.compute.Compute.connect") as mock_connect:
|
||||
async_run(controller.start())
|
||||
assert mock.called
|
||||
assert "local" in controller.computes
|
||||
assert "vm" in controller.computes
|
||||
assert len(controller.computes) == 2 # Local compute and vm are created
|
||||
@@ -541,6 +542,6 @@ def test_autoidlepc(controller, async_run):
|
||||
controller._computes["local"] = AsyncioMagicMock()
|
||||
node_mock = AsyncioMagicMock()
|
||||
with asyncio_patch("gns3server.controller.Project.add_node", return_value=node_mock):
|
||||
async_run(controller.autoidlepc("local", "c7200", "test.bin"))
|
||||
async_run(controller.autoidlepc("local", "c7200", "test.bin", 512))
|
||||
assert node_mock.dynamips_auto_idlepc.called
|
||||
assert len(controller.projects) == 0
|
||||
@@ -351,3 +351,69 @@ def test_export_keep_compute_id(tmpdir, project, async_run):
|
||||
topo = json.loads(myfile.read().decode())["topology"]
|
||||
assert topo["nodes"][0]["compute_id"] == "6b7149c8-7d6e-4ca0-ab6b-daa8ab567be0"
|
||||
assert len(topo["computes"]) == 1
|
||||
|
||||
def test_export_images_from_vm(tmpdir, project, async_run, controller):
|
||||
"""
|
||||
If data is on a remote server export it locally before
|
||||
sending it in the archive.
|
||||
"""
|
||||
|
||||
compute = MagicMock()
|
||||
compute.id = "vm"
|
||||
compute.list_files = AsyncioMagicMock(return_value=[
|
||||
{"path": "vm-1/dynamips/test"}
|
||||
])
|
||||
|
||||
# Fake file that will be download from the vm
|
||||
mock_response = AsyncioMagicMock()
|
||||
mock_response.content = AsyncioBytesIO()
|
||||
async_run(mock_response.content.write(b"HELLO"))
|
||||
mock_response.content.seek(0)
|
||||
mock_response.status = 200
|
||||
compute.download_file = AsyncioMagicMock(return_value=mock_response)
|
||||
|
||||
mock_response = AsyncioMagicMock()
|
||||
mock_response.content = AsyncioBytesIO()
|
||||
async_run(mock_response.content.write(b"IMAGE"))
|
||||
mock_response.content.seek(0)
|
||||
mock_response.status = 200
|
||||
compute.download_image = AsyncioMagicMock(return_value=mock_response)
|
||||
|
||||
project._project_created_on_compute.add(compute)
|
||||
|
||||
path = project.path
|
||||
os.makedirs(os.path.join(path, "vm-1", "dynamips"))
|
||||
|
||||
topology = {
|
||||
"topology": {
|
||||
"nodes": [
|
||||
{
|
||||
"compute_id": "vm",
|
||||
"properties": {
|
||||
"image": "test.image"
|
||||
},
|
||||
"node_type": "dynamips"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# The .gns3 should be renamed project.gns3 in order to simplify import
|
||||
with open(os.path.join(path, "test.gns3"), 'w+') as f:
|
||||
f.write(json.dumps(topology))
|
||||
|
||||
z = async_run(export_project(project, str(tmpdir), include_images=True))
|
||||
assert compute.list_files.called
|
||||
|
||||
with open(str(tmpdir / 'zipfile.zip'), 'wb') as f:
|
||||
for data in z:
|
||||
f.write(data)
|
||||
|
||||
with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip:
|
||||
with myzip.open("vm-1/dynamips/test") as myfile:
|
||||
content = myfile.read()
|
||||
assert content == b"HELLO"
|
||||
|
||||
with myzip.open("images/dynamips/test.image") as myfile:
|
||||
content = myfile.read()
|
||||
assert content == b"IMAGE"
|
||||
@@ -70,7 +70,8 @@ def test_update_settings(controller, async_run):
|
||||
"vmname": "GNS3 VM"
|
||||
}
|
||||
with asyncio_patch("gns3server.controller.gns3vm.vmware_gns3_vm.VMwareGNS3VM.start"):
|
||||
async_run(vm.auto_start_vm())
|
||||
with asyncio_patch("gns3server.controller.gns3vm.GNS3VM._check_network") as mock_check_network:
|
||||
async_run(vm.auto_start_vm())
|
||||
assert "vm" in controller.computes
|
||||
async_run(vm.update_settings({"enable": False}))
|
||||
assert "vm" not in controller.computes
|
||||
@@ -80,7 +81,9 @@ def test_auto_start(async_run, controller, dummy_gns3vm, dummy_engine):
|
||||
"""
|
||||
When start the compute should be add to the controller
|
||||
"""
|
||||
async_run(dummy_gns3vm.auto_start_vm())
|
||||
|
||||
with asyncio_patch("gns3server.controller.gns3vm.GNS3VM._check_network") as mock_check_network:
|
||||
async_run(dummy_gns3vm.auto_start_vm())
|
||||
assert dummy_engine.start.called
|
||||
assert controller.computes["vm"].name == "GNS3 VM (Test VM)"
|
||||
assert controller.computes["vm"].host == "vm.local"
|
||||
|
||||
@@ -195,7 +195,7 @@ def test_create(node, compute, project, async_run):
|
||||
"startup_script": "echo test",
|
||||
"name": "demo"
|
||||
}
|
||||
compute.post.assert_called_with("/projects/{}/vpcs/nodes".format(node.project.id), data=data, timeout=120)
|
||||
compute.post.assert_called_with("/projects/{}/vpcs/nodes".format(node.project.id), data=data, timeout=1200)
|
||||
assert node._console == 2048
|
||||
assert node._properties == {"startup_script": "echo test"}
|
||||
|
||||
@@ -244,7 +244,7 @@ def test_create_base_script(node, config, compute, tmpdir, async_run):
|
||||
"startup_script": "hostname test",
|
||||
"name": "demo"
|
||||
}
|
||||
compute.post.assert_called_with("/projects/{}/vpcs/nodes".format(node.project.id), data=data, timeout=120)
|
||||
compute.post.assert_called_with("/projects/{}/vpcs/nodes".format(node.project.id), data=data, timeout=1200)
|
||||
|
||||
|
||||
def test_symbol(node, symbols_dir):
|
||||
@@ -445,7 +445,7 @@ def test_create_without_console(node, compute, project, async_run):
|
||||
"startup_script": "echo test",
|
||||
"name": "demo"
|
||||
}
|
||||
compute.post.assert_called_with("/projects/{}/vpcs/nodes".format(node.project.id), data=data, timeout=120)
|
||||
compute.post.assert_called_with("/projects/{}/vpcs/nodes".format(node.project.id), data=data, timeout=1200)
|
||||
assert node._console == 2048
|
||||
assert node._properties == {"test_value": "success", "startup_script": "echo test"}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ def test_add_node_local(async_run, controller):
|
||||
data={'node_id': node.id,
|
||||
'startup_script': 'test.cfg',
|
||||
'name': 'test'},
|
||||
timeout=120)
|
||||
timeout=1200)
|
||||
assert compute in project._project_created_on_compute
|
||||
controller.notification.emit.assert_any_call("node.created", node.__json__())
|
||||
|
||||
@@ -181,7 +181,7 @@ def test_add_node_non_local(async_run, controller):
|
||||
data={'node_id': node.id,
|
||||
'startup_script': 'test.cfg',
|
||||
'name': 'test'},
|
||||
timeout=120)
|
||||
timeout=1200)
|
||||
assert compute in project._project_created_on_compute
|
||||
controller.notification.emit.assert_any_call("node.created", node.__json__())
|
||||
|
||||
@@ -222,7 +222,7 @@ def test_add_node_from_appliance(async_run, controller):
|
||||
'name': 'Test-1',
|
||||
'a': 1,
|
||||
},
|
||||
timeout=120)
|
||||
timeout=1200)
|
||||
assert compute in project._project_created_on_compute
|
||||
controller.notification.emit.assert_any_call("node.created", node.__json__())
|
||||
|
||||
@@ -233,7 +233,7 @@ def test_add_node_from_appliance(async_run, controller):
|
||||
'name': 'Test-2',
|
||||
'a': 1
|
||||
},
|
||||
timeout=120)
|
||||
timeout=1200)
|
||||
|
||||
|
||||
def test_delete_node(async_run, controller):
|
||||
|
||||
@@ -79,7 +79,7 @@ def test_iou_create_with_params(http_compute, project, base_params):
|
||||
params["ethernet_adapters"] = 0
|
||||
params["l1_keepalives"] = True
|
||||
params["startup_config_content"] = "hostname test"
|
||||
params["use_default_iou_values"] = True
|
||||
params["use_default_iou_values"] = False
|
||||
|
||||
response = http_compute.post("/projects/{project_id}/iou/nodes".format(project_id=project.id), params, example=True)
|
||||
assert response.status == 201
|
||||
@@ -91,7 +91,7 @@ def test_iou_create_with_params(http_compute, project, base_params):
|
||||
assert response.json["ram"] == 1024
|
||||
assert response.json["nvram"] == 512
|
||||
assert response.json["l1_keepalives"] is True
|
||||
assert response.json["use_default_iou_values"] is True
|
||||
assert response.json["use_default_iou_values"] is False
|
||||
|
||||
with open(startup_config_file(project, response.json)) as f:
|
||||
assert f.read() == "hostname test"
|
||||
|
||||
@@ -232,10 +232,11 @@ def test_compute_autoidlepc(http_controller, controller):
|
||||
|
||||
params = {
|
||||
"platform": "c7200",
|
||||
"image": "test.bin"
|
||||
"image": "test.bin",
|
||||
"ram": 512
|
||||
}
|
||||
with asyncio_patch("gns3server.controller.Controller.autoidlepc", return_value={"idlepc": "0x606de20c"}) as mock:
|
||||
response = http_controller.post("/computes/my_compute_id/autoidlepc", params, example=True)
|
||||
response = http_controller.post("/computes/my_compute_id/auto_idlepc", params, example=True)
|
||||
assert mock.called
|
||||
assert response.status == 200
|
||||
|
||||
|
||||
Reference in new issue
Block a user