Compare commits

...
56 Commits
Author SHA1 Message Date
ziajka 5dd0414ab3 Release v2.1.1 2017-12-22 13:27:20 +01:00
grossmj e8353e68bb Merge remote-tracking branch 'origin/2.1' into 2.1 2017-12-21 09:38:28 +01:00
grossmj 23c63bbd4d Protect variable replacement for Qemu options. Escape double quotes. 2017-12-21 09:38:18 +01:00
ziajka dadf11f69b Fix tests 2017-12-21 09:37:48 +01:00
ziajka 3efe753eee Add proper exception when cannot find tunnel on QEMU, Fixes: #1241 2017-12-21 08:55:49 +01:00
ziajka f48420af58 Increase timeout for creation of image, Ref. #2239 2017-12-21 08:46:20 +01:00
grossmj 79bca29b93 Protect variable replacement for Qemu options. 2017-12-20 20:46:16 +01:00
grossmj 0e4865e049 Bump version to 2.1.1dev2 2017-12-20 11:20:07 +01:00
grossmj 26567d9164 Merge remote-tracking branch 'origin/2.1' into 2.1 2017-12-18 12:08:23 +01:00
grossmj a8177d7afa Fix tests more reliably. Ref #0df997d. 2017-12-18 12:08:14 +01:00
ziajka a393e7f723 Merge pull request #1205 from GNS3/aiohttp-2.3.1
aiohttp 2.3 support.
2017-12-18 11:09:16 +01:00
grossmj 0df997d232 Fix tests. 2017-12-17 23:06:19 +01:00
grossmj 630afc5469 Do not overwrites persistent Docker volumes. Fixes #2358. 2017-12-17 22:35:26 +01:00
grossmj 3e3e1df051 Allow users to see an error when the server cannot stream a PCAP file. 2017-12-07 12:28:01 -06:00
grossmj 3a1ba8f42d Fix issue with Qemu + SPICE when IPv4 is not enabled. 2017-12-07 12:02:41 -06:00
grossmj 0a72e0db87 Fix more GNS3 VM related tests. 2017-12-05 20:38:48 -06:00
grossmj e3b3427cc6 Fix GNS3 VM start test. 2017-12-05 20:30:28 -06:00
grossmj dde2003168 Fix tests. 2017-12-05 16:56:50 -06:00
grossmj cfe8e9e85c Warn users if the GNS3 VM and local server are not in the same subnet. Fixes #1231. 2017-12-05 16:43:44 -06:00
grossmj 1699ce5d1c Add missing appliance files. 2017-11-27 13:43:47 +07:00
grossmj d0850927d0 Update appliance files. 2017-11-27 13:42:26 +07:00
grossmj 745532bf23 Fix auto idlepc test. 2017-11-23 23:46:22 +07:00
grossmj 78cf0309a0 Merge remote-tracking branch 'origin/2.1' into 2.1 2017-11-23 23:29:09 +07:00
grossmj 851fcf5c71 Fix compute auto idlepc test. 2017-11-23 23:28:52 +07:00
Jeremy Grossmann a80355998d Merge pull request #1230 from GNS3/consitance-about-exc
Keep consistance of aiohttp.web.HTTPForbidden() execution
2017-11-23 23:02:42 +07:00
grossmj e54d574e47 Fix auto idle-pc from preferences. 2017-11-23 23:00:31 +07:00
ziajka fe60c414b9 Keep consistance of aiohttp.web.HTTPForbidden() execution 2017-11-23 16:28:10 +01:00
grossmj efbf7728ea Fix Docker tests. 2017-11-23 11:27:17 +07:00
grossmj 061af38b5a Make sure connected links are removed when a node is deleted. 2017-11-23 11:19:41 +07:00
grossmj f48549a997 Validate idle-pc values for auto idle-pc feature. 2017-11-23 10:40:51 +07:00
grossmj 958ab2294c Merge remote-tracking branch 'origin/2.1' into 2.1 2017-11-23 10:04:46 +07:00
grossmj dd89b09f84 Fix error when updating packet filter on stopped Docker link. Fixes #1229. 2017-11-23 10:04:32 +07:00
Jeremy Grossmann 642536a070 Merge pull request #1228 from GNS3/es-console
Close telnet console after stopping the node. Ref gui/#2330
2017-11-20 22:02:58 +07:00
ziajka 860ca3b35d Remotely close telnet console. Ref #2330 2017-11-20 15:28:07 +01:00
ziajka 96a0b52cf8 EthernetSwitch closing connections, Ref: gui/#2330 2017-11-20 13:51:07 +01:00
Jeremy Grossmann 7c90c513d0 Merge pull request #1227 from GNS3/improved-export-project
Export files from remote server, Fixes: gui/#2271
2017-11-20 17:19:20 +07:00
ziajka fe59c937d5 Merge branch '2.1' into improved-export-project 2017-11-20 11:15:04 +01:00
ziajka b48f5df53f iExport files from remote server, Fixes: gui/#2271 2017-11-20 10:47:03 +01:00
grossmj 3e2e8e61f7 New option: require KVM. If false, Qemu VMs will not be prevented to run without KVM. 2017-11-19 12:39:37 +07:00
grossmj 068077c594 Remove forgotten debug. 2017-11-18 17:36:39 +07:00
grossmj e08aebf1f0 Implement variable replacement for Qemu VM options. 2017-11-18 17:36:11 +07:00
grossmj cfbcc1194d Avoid duplicate "-nographic" option. 2017-11-18 16:22:29 +07:00
grossmj 035a078b5e Show qemu-img stdout in case of an error. 2017-11-17 18:13:34 +07:00
grossmj cf14deb2fa Fix IOU tests. 2017-11-16 17:07:51 +07:00
grossmj e1fe34ca07 Use the correct NVRAM amount when pushing private config to IOU. 2017-11-16 16:52:19 +07:00
grossmj d3e55520d9 Merge remote-tracking branch 'remotes/origin/master' into 2.1 2017-11-16 15:03:20 +07:00
grossmj 4477cd4dfd Merge remote-tracking branch 'origin/2.1' 2017-11-16 14:54:53 +07:00
grossmj 967798a7de Check and fix corrupt Qemu disk images. Fixes #2301. 2017-11-16 14:54:37 +07:00
ziajka 61acb939a4 Update pyup config to use 2.2 branch 2017-11-15 13:20:31 +01:00
grossmj 8c11b649e5 Update warning messages when connecting to non custom adapter for VMware VMs. 2017-11-15 16:55:19 +07:00
grossmj b14e2e73ed Fix "Can't use VirtualBox VM when an interface is managed by VirtualBox". Fixes #2335. 2017-11-15 16:41:33 +07:00
ziajka 2235a8158f Update requirements.txt 2017-11-15 09:00:14 +01:00
grossmj 9afe756462 Add low disk space warning when creating a new project. 2017-11-14 18:22:59 +07:00
ziajka 135c529d4b Development on 2.1.1dev1 2017-11-09 10:49:56 +01:00
ziajka ce219e81ea Development on 2.1.0dev11 2017-11-09 10:48:48 +01:00
ziajka a7412d1c87 aiohttp 2.3.1 dependency 2017-10-26 16:29:01 +02:00
71 changed files with 1232 additions and 142 deletions

No files matched your search

+1 -1
View File
@@ -1,2 +1,2 @@
branch:
2.0
2.2
+30
View File
@@ -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
+2
View File
@@ -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
+28
View File
@@ -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": {
+15
View File
@@ -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": {
+45
View File
@@ -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"
}
}
]
}
+41 -2
View File
@@ -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": {
+15
View File
@@ -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": {
+16 -1
View File
@@ -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": {
+42
View File
@@ -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": {
+14
View File
@@ -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": {
+14
View File
@@ -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": {
+14
View File
@@ -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": {
+42
View File
@@ -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": {
+14
View File
@@ -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": {
+15
View File
@@ -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": {
+16
View File
@@ -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": {
+13
View File
@@ -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": {
+15
View File
@@ -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": {
+13
View File
@@ -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": {
+14
View File
@@ -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": {
+14
View File
@@ -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": {
+15
View File
@@ -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": {
+13
View File
@@ -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": {
+18 -1
View File
@@ -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": {
+6 -4
View File
@@ -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
+5 -3
View File
@@ -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):
+9 -9
View File
@@ -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
+5 -3
View File
@@ -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()
+28 -2
View File
@@ -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
+26
View File
@@ -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
+77 -16
View File
@@ -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)])
+27 -12
View File
@@ -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):
+11 -4
View File
@@ -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:
+4 -3
View File
@@ -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)
+23 -1
View File
@@ -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:
+82 -13
View File
@@ -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)
+32
View File
@@ -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):
"""
+4 -1
View File
@@ -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:
+1 -1
View File
@@ -325,7 +325,7 @@ class Node:
if self._node_type == "docker":
timeout = None
else:
timeout = 120
timeout = 1200
trial = 0
while trial != 6:
try:
+8 -4
View File
@@ -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)
+1 -1
View File
@@ -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)
+34 -2
View File
@@ -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
+2 -2
View File
@@ -23,8 +23,8 @@
# or negative for a release candidate or beta (after the base version
# number has been incremented)
__version__ = "2.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
View File
@@ -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)
+8 -3
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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"
+2
View File
@@ -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",
+2 -2
View File
@@ -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}
+5 -4
View File
@@ -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
+66
View File
@@ -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"
+5 -2
View File
@@ -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"
+3 -3
View File
@@ -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"}
+4 -4
View File
@@ -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):
+2 -2
View File
@@ -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