mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 14:01:15 +02:00
Merge 2.1 into 2.2 branch
This commit is contained in:
1 parent
2a5f3221b9
commit
658aa4bae9
69 files changed
+846
-448
No files matched your search
@@ -9,6 +9,7 @@
|
||||
"product_url": "https://www.centos.org/download/",
|
||||
"registry_version": 5,
|
||||
"status": "stable",
|
||||
"availability": "free",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Username: osboxes.org\nPassword: osboxes.org",
|
||||
|
||||
@@ -6,15 +6,16 @@
|
||||
"vendor_url": "https://www.checkpoint.com",
|
||||
"documentation_url": "http://downloads.checkpoint.com/dc/download.htm?ID=26770",
|
||||
"product_name": "Gaia",
|
||||
"registry_version": 3,
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "At boot choose the install on disk options. You need to open quickly the terminal after launching the appliance if you want to see the menu. You need a web browser in order to finalize the installation. You can use the firefox appliance for this.",
|
||||
"qemu": {
|
||||
"cpus": 2,
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 8,
|
||||
"ram": 2048,
|
||||
"ram": 4096,
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "dc",
|
||||
@@ -44,33 +45,33 @@
|
||||
"download_url": "https://supportcenter.checkpoint.com/supportcenter/portal?eventSubmit_doGoviewsolutiondetails=&solutionid=sk104859"
|
||||
},
|
||||
{
|
||||
"filename": "empty8G.qcow2",
|
||||
"filename": "empty100G.qcow2",
|
||||
"version": "1.0",
|
||||
"md5sum": "f1d2c25b6990f99bd05b433ab603bdb4",
|
||||
"md5sum": "1e6409a4523ada212dea2ebc50e50a65",
|
||||
"filesize": 197120,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/",
|
||||
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty8G.qcow2/download"
|
||||
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty100G.qcow2/download"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "80.10",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"hda_disk_image": "empty100G.qcow2",
|
||||
"cdrom_image": "Check_Point_R80.10_T421_Gaia.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "77.30",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"hda_disk_image": "empty100G.qcow2",
|
||||
"cdrom_image": "Check_Point_R77.30_T204_Install_and_Upgrade.Gaia.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "77.20",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"hda_disk_image": "empty100G.qcow2",
|
||||
"cdrom_image": "Check_Point_R77.20_T124_Install.Gaia.iso"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,23 +25,30 @@
|
||||
{
|
||||
"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"
|
||||
"md5sum": "bad9000d4ae8317bbc99a34a8cdd2eb4",
|
||||
"filesize": 884539392,
|
||||
"download_url": "https://software.cisco.com/download/release.html?mdfid=284364978&flowid=39582&softwareid=282046477&release=Fuji-16.7.1"
|
||||
},
|
||||
{
|
||||
"filename": "csr1000v-universalk9.16.06.02-serial.qcow2",
|
||||
"version": "16.6.2",
|
||||
"md5sum": "11e393b31ab9d1ace8e5f7551c491ba2",
|
||||
"filesize": 1570242560,
|
||||
"download_url": "https://software.cisco.com/download/release.html?mdfid=284364978&flowid=39582&softwareid=282046477&release=Everest-16.6.2"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
"download_url": "https://software.cisco.com/download/release.html?mdfid=284364978&flowid=39582&softwareid=282046477&release=Everest-16.6.1"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
"download_url": "https://software.cisco.com/download/release.html?mdfid=284364978&flowid=39582&softwareid=282046477&release=Everest-16.5.2"
|
||||
},
|
||||
{
|
||||
"filename": "csr1000v-universalk9.16.5.1b-serial.qcow2",
|
||||
@@ -93,6 +100,12 @@
|
||||
"hda_disk_image": "csr1000v-universalk9.16.07.01-serial.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "16.6.2",
|
||||
"images": {
|
||||
"hda_disk_image": "csr1000v-universalk9.16.06.02-serial.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "16.6.1",
|
||||
"images": {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"product_url": "http://www.cisco.com/c/en/us/td/docs/security/firepower/quick_start/kvm/fmcv-kvm-qsg.html",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"availability": "service-contract",
|
||||
"maintainer": "Community",
|
||||
"maintainer_email":"",
|
||||
"usage": "BE PATIENT\nOn first boot FMCv generates about 6GB of data. This can take 30 minutes or more. Plan on a long wait after the following line in the boot up:\n\n usbcore: registered new interface driver usb-storage\n\nInitial IP address: 192.168.45.45.\n\nDefault username/password: admin/Admin123.",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"product_url": "http://www.cisco.com/c/en/us/td/docs/security/firepower/quick_start/kvm/ftdv-kvm-qsg.html",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"availability": "service-contract",
|
||||
"maintainer": "Community",
|
||||
"maintainer_email": "",
|
||||
"usage": "Default username/password: admin/Admin123.",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"product_url": "http://www.cisco.com/c/en/us/support/security/ngips-virtual-appliance/tsd-products-support-series-home.html",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"availability": "service-contract",
|
||||
"maintainer": "Community",
|
||||
"maintainer_email": "",
|
||||
"usage": "Default username/password: admin/Admin123.",
|
||||
|
||||
@@ -22,6 +22,13 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ClearOS-7.4-DVD-x86_64.iso",
|
||||
"version": "7.4",
|
||||
"md5sum": "826da592f9cd4b59f5fc996ff2d569f1",
|
||||
"filesize": 1029701632,
|
||||
"download_url": "https://www.clearos.com/clearfoundation/software/clearos-downloads"
|
||||
},
|
||||
{
|
||||
"filename": "ClearOS-7.3-DVD-x86_64.iso",
|
||||
"version": "7.3",
|
||||
@@ -46,6 +53,13 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "7.4",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2",
|
||||
"cdrom_image": "ClearOS-7.4-DVD-x86_64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "7.3",
|
||||
"images": {
|
||||
|
||||
@@ -21,6 +21,15 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "coreos_production_qemu_image.1632.2.1.img",
|
||||
"version": "1632.2.1",
|
||||
"md5sum": "facd05ca85eb87e2dc6aefd6779f6806",
|
||||
"filesize": 885719040,
|
||||
"download_url": "http://stable.release.core-os.net/amd64-usr/1632.2.1/",
|
||||
"direct_download_url": "http://stable.release.core-os.net/amd64-usr/1632.2.1/coreos_production_qemu_image.img.bz2",
|
||||
"compression": "bzip2"
|
||||
},
|
||||
{
|
||||
"filename": "coreos_production_qemu_image.1576.4.0.img",
|
||||
"version": "1576.4.0",
|
||||
@@ -149,6 +158,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "1632.2.1",
|
||||
"images": {
|
||||
"hda_disk_image": "coreos_production_qemu_image.1576.4.0.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "1576.4.0",
|
||||
"images": {
|
||||
|
||||
@@ -23,6 +23,14 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "cumulus-linux-3.5.2-vx-amd64.qcow2",
|
||||
"version": "3.5.2",
|
||||
"md5sum": "87d1d8b297e5ebd77924669dfb7e4c9f",
|
||||
"filesize": 996605952,
|
||||
"download_url": "https://cumulusnetworks.com/cumulus-vx/download/",
|
||||
"direct_download_url": "http://cumulusfiles.s3.amazonaws.com/cumulus-linux-3.5.0-vx-amd64.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "cumulus-linux-3.5.0-vx-amd64.qcow2",
|
||||
"version": "3.5.0",
|
||||
@@ -133,6 +141,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "3.5.2",
|
||||
"images": {
|
||||
"hda_disk_image": "cumulus-linux-3.5.2-vx-amd64.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "3.5.0",
|
||||
"images": {
|
||||
|
||||
@@ -27,6 +27,13 @@
|
||||
"options": "-smp 2 -cpu host"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "BIGIP-13.1.0.2.0.0.6.qcow2",
|
||||
"version": "13.1.0 HF2",
|
||||
"md5sum": "d29eb861d8906fc36f88d9861a0055f4",
|
||||
"filesize": 4363649024,
|
||||
"download_url": "https://downloads.f5.com/esd/serveDownload.jsp?path=/big-ip/big-ip_v13.x/13.1.0/english/13.1.0.2_virtual-edition/&sw=BIG-IP&pro=big-ip_v13.x&ver=13.1.0&container=13.1.0.2_Virtual-Edition&file=BIGIP-13.1.0.2.0.0.6.ALL.qcow2.zip"
|
||||
},
|
||||
{
|
||||
"filename": "BIGIP-13.1.0.1.0.0.8.qcow2",
|
||||
"version": "13.1.0 HF1",
|
||||
@@ -114,6 +121,13 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "13.1.0 HF2",
|
||||
"images": {
|
||||
"hda_disk_image": "BIGIP-13.1.0.2.0.0.6.qcow2",
|
||||
"hdb_disk_image": "empty100G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "13.1.0 HF1",
|
||||
"images": {
|
||||
|
||||
@@ -34,6 +34,13 @@
|
||||
"filesize": 30998528,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAD_KVM-V400-build0989-FORTINET.out.kvm-boot.qcow2",
|
||||
"version": "4.8.4",
|
||||
"md5sum": "c1926d5979ef24d9d14d3394c0bb832b",
|
||||
"filesize": 72810496,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FAD_KVM-V400-build0983-FORTINET.out.kvm-boot.qcow2",
|
||||
"version": "4.8.3",
|
||||
@@ -148,6 +155,13 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "4.8.4",
|
||||
"images": {
|
||||
"hda_disk_image": "FAD_KVM-V400-build0989-FORTINET.out.kvm-boot.qcow2",
|
||||
"hdb_disk_image": "FAD_KVM-v400-FORTINET.out.kvm-data.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "4.8.3",
|
||||
"images": {
|
||||
|
||||
@@ -54,6 +54,13 @@
|
||||
"filesize": 38760448,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FGT_VM64_KVM-v5-build1183-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.4.8",
|
||||
"md5sum": "c1eb02996a0919c934785d5f48df9507",
|
||||
"filesize": 38608896,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FGT_VM64_KVM-v5-build6446-FORTINET.out.kvm.qcow2",
|
||||
"version": "5.4.7",
|
||||
@@ -204,6 +211,13 @@
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.4.8",
|
||||
"images": {
|
||||
"hda_disk_image": "FGT_VM64_KVM-v5-build1183-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "5.4.7",
|
||||
"images": {
|
||||
|
||||
@@ -27,6 +27,13 @@
|
||||
"options": "-smp 2"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "FSA_KVM-v200-build0329-FORTINET.out.kvm.qcow2",
|
||||
"version": "2.5.1",
|
||||
"md5sum": "782ba56a644d78da59b89f4ac91bd319",
|
||||
"filesize": 114491904,
|
||||
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
|
||||
},
|
||||
{
|
||||
"filename": "FSA_KVM-v200-build0261-FORTINET.out.kvm.qcow2",
|
||||
"version": "2.4.1",
|
||||
@@ -71,6 +78,13 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "2.5.1",
|
||||
"images": {
|
||||
"hda_disk_image": "FSA_KVM-v200-build0329-FORTINET.out.kvm.qcow2",
|
||||
"hdb_disk_image": "FSA_v200-datadrive.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2.4.1",
|
||||
"images": {
|
||||
|
||||
@@ -24,6 +24,14 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "FreeNAS-11.1-U1.iso",
|
||||
"version": "11.1 U1",
|
||||
"md5sum": "ccbd9990a5878d35c6bc0cc6eea34b16",
|
||||
"filesize": 626601984,
|
||||
"download_url": "http://www.freenas.org/download/",
|
||||
"direct_download_url": "http://download.freenas.org/11/11.1-RELEASE/x64/FreeNAS-11.1-RELEASE.iso"
|
||||
},
|
||||
{
|
||||
"filename": "FreeNAS-11.1-RELEASE.iso",
|
||||
"version": "11.1",
|
||||
@@ -34,7 +42,7 @@
|
||||
},
|
||||
{
|
||||
"filename": "FreeNAS-11.0-U4.iso",
|
||||
"version": "11.0-U4",
|
||||
"version": "11.0 U4",
|
||||
"md5sum": "4c210f1a6510d1fa95257d81ef569ff8",
|
||||
"filesize": 567312384,
|
||||
"download_url": "http://www.freenas.org/download/",
|
||||
@@ -42,7 +50,7 @@
|
||||
},
|
||||
{
|
||||
"filename": "FreeNAS-9.10.1-U4.iso",
|
||||
"version": "9.10",
|
||||
"version": "9.10 U4",
|
||||
"md5sum": "b4fb14513dcbb4eb4c5596c5911ca9cc",
|
||||
"filesize": 533098496,
|
||||
"download_url": "http://www.freenas.org/download/",
|
||||
@@ -58,6 +66,14 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "11.1 U1",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2",
|
||||
"cdrom_image": "FreeNAS-11.1-U1.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "11.1",
|
||||
"images": {
|
||||
@@ -67,7 +83,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "11.0",
|
||||
"name": "11.0 U4",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2",
|
||||
@@ -75,7 +91,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "9.10",
|
||||
"name": "9.10 U4",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2",
|
||||
|
||||
@@ -24,6 +24,15 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ipfire-2.19.1gb-ext4-scon.x86_64-full-core117.img",
|
||||
"version": "2.19.117",
|
||||
"md5sum": "657673d88b94ed7d22332aebe817bc86",
|
||||
"filesize": 1063256064,
|
||||
"download_url": "http://www.ipfire.org/download",
|
||||
"direct_download_url": "https://downloads.ipfire.org/releases/ipfire-2.x/2.19-core117/ipfire-2.19.1gb-ext4-scon.x86_64-full-core117.img.gz",
|
||||
"compression": "gzip"
|
||||
},
|
||||
{
|
||||
"filename": "ipfire-2.19.1gb-ext4-scon.x86_64-full-core116.img",
|
||||
"version": "2.19.116",
|
||||
@@ -53,6 +62,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "2.19.117",
|
||||
"images": {
|
||||
"hda_disk_image": "ipfire-2.19.1gb-ext4-scon.x86_64-full-core117.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2.19.116",
|
||||
"images": {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "Junos Space",
|
||||
"category": "guest",
|
||||
"description": "Junos Space Network Management Platform works with Juniper's management applications to simplify and automate management of Juniper's switching, routing, and security devices. As part of a complete solution, the platform provides broad fault, configuration, accounting, performance, and security management (FCAPS) capability, same day support for new devices and Junos OS releases, a task-specific user interface, and northbound APIs for integration with existing network management systems (NMS) or operations/business support systems (OSS/BSS).\n\nThe platform helps network operators at enterprises and service providers scale operations, reduce complexity, and enable new applications and services to be brought to market quickly, through multilayered network abstractions, operator-centric automation schemes, and a simple point-and-click UI.",
|
||||
"vendor_name": "Juniper",
|
||||
"vendor_url": "https://www.juniper.net/us/en/",
|
||||
"documentation_url": "http://www.juniper.net/techpubs/",
|
||||
"product_name": "Junos Space",
|
||||
"product_url": "https://www.juniper.net/us/en/dm/free-vqfx-trial/",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"symbol": "juniper-vqfx.svg",
|
||||
"usage": "16 GB RAM is the bare minimum; you should use 32/64 GB in production deplyments.\nDefault credentials:\n- CLI: admin / abc123\n- WebUI: super / juniper123",
|
||||
"port_name_format": "em{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 4,
|
||||
"ram": 16384,
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"kvm": "require",
|
||||
"options": "-smp 4 -nographic"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "space-17.2R1.4.qcow2",
|
||||
"version": "17.2R1.4",
|
||||
"md5sum": "4124fa756c3a78be0619e876b8ee687e",
|
||||
"filesize": 5150474240,
|
||||
"download_url": "https://www.juniper.net/support/downloads/?p=space#sw"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "17.2R1.4",
|
||||
"images": {
|
||||
"hda_disk_image": "space-17.2R1.4.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
"product_url": "https://www.opensuse.org/#Leap",
|
||||
"registry_version": 4,
|
||||
"status": "stable",
|
||||
"availability": "free",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Username: osboxes\nPassword: osboxes.org\n\nroot password: osboxes.org",
|
||||
|
||||
@@ -22,6 +22,15 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "PacketFenceZEN_USB-7.4.0.img",
|
||||
"version": "7.4.0",
|
||||
"md5sum": "83951211540f16dd5813c26955c52429",
|
||||
"filesize": 3221225472,
|
||||
"download_url": "https://packetfence.org/download.html#/zen",
|
||||
"direct_download_url": "https://sourceforge.net/projects/packetfence/files/PacketFence%20ZEN/7.4.0/PacketFenceZEN_USB-7.4.0.tar.bz2/download",
|
||||
"compression": "bzip2"
|
||||
},
|
||||
{
|
||||
"filename": "PacketFenceZEN_USB-7.3.0.img",
|
||||
"version": "7.3.0",
|
||||
@@ -96,6 +105,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "7.4.0",
|
||||
"images": {
|
||||
"hda_disk_image": "PacketFenceZEN_USB-7.4.0.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "7.3.0",
|
||||
"images": {
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"name": "Ubuntu Cloud Guest",
|
||||
"category": "guest",
|
||||
"description": "The term 'Ubuntu Cloud Guest' refers to the Official Ubuntu images that are available at http://cloud-images.ubuntu.com . These images are built by Canonical. They are then registered on EC2, and compressed tarfiles are made also available for download. For using those images on a public cloud such as Amazon EC2, you simply choose an image and launch it. To use those images on a private cloud, or to run the image on a local hypervisor (such as KVM) you would need to download those images and either publish them to your private cloud, or launch them directly on a hypervisor. The following sections explain in more details how to perform each of those actions",
|
||||
"vendor_name": "Canonical Inc.",
|
||||
"vendor_url": "https://www.ubuntu.com",
|
||||
"documentation_url": "https://help.ubuntu.com/community/UEC/Images",
|
||||
"product_name": "Ubuntu Cloud Guest",
|
||||
"product_url": "https://www.ubuntu.com/cloud",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Username: ubuntu\nPassword: ubuntu",
|
||||
"port_name_format": "Ethernet{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 1,
|
||||
"ram": 1024,
|
||||
"hda_disk_interface": "virtio",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "c",
|
||||
"kvm": "require",
|
||||
"options": "-nographic"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ubuntu-17.10-server-cloudimg-amd64.img",
|
||||
"version": "17.10",
|
||||
"md5sum": "5d221878d8b2e49c5de7ebb58a2b35e3",
|
||||
"filesize": 318373888,
|
||||
"download_url": "https://cloud-images.ubuntu.com/releases/17.10/release/"
|
||||
},
|
||||
{
|
||||
"filename": "ubuntu-17.04-server-cloudimg-amd64.img",
|
||||
"version": "17.04",
|
||||
"md5sum": "d4da8157dbf2e64f2fa1fb5d121398e5",
|
||||
"filesize": 351993856,
|
||||
"download_url": "https://cloud-images.ubuntu.com/releases/17.04/release/"
|
||||
},
|
||||
{
|
||||
"filename": "ubuntu-16.04-server-cloudimg-amd64-disk1.img",
|
||||
"version": "16.04.3",
|
||||
"md5sum": "bd0c168a83b1f483bd240b3d874edd6c",
|
||||
"filesize": 288686080,
|
||||
"download_url": "https://cloud-images.ubuntu.com/releases/16.04/release/"
|
||||
},
|
||||
{
|
||||
"filename": "ubuntu-14.04-server-cloudimg-amd64-disk1.img",
|
||||
"version": "14.04.5",
|
||||
"md5sum": "d7b4112c7d797e5e77ef9995d06a76f1",
|
||||
"filesize": 262406656,
|
||||
"download_url": "https://cloud-images.ubuntu.com/releases/14.04/release/"
|
||||
},
|
||||
{
|
||||
"filename": "ubuntu-cloud-init-data.iso",
|
||||
"version": "1.0",
|
||||
"md5sum": "328469100156ae8dbf262daa319c27ff",
|
||||
"filesize": 131072,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/ubuntu-cloud-init-data.iso/download"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "17.10",
|
||||
"images": {
|
||||
"hda_disk_image": "ubuntu-17.10-server-cloudimg-amd64.img",
|
||||
"cdrom_image": "ubuntu-cloud-init-data.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "17.04",
|
||||
"images": {
|
||||
"hda_disk_image": "ubuntu-17.04-server-cloudimg-amd64.img",
|
||||
"cdrom_image": "ubuntu-cloud-init-data.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "16.04 (LTS)",
|
||||
"images": {
|
||||
"hda_disk_image": "ubuntu-16.04-server-cloudimg-amd64-disk1.img",
|
||||
"cdrom_image": "ubuntu-cloud-init-data.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "14.04 (LTS)",
|
||||
"images": {
|
||||
"hda_disk_image": "ubuntu-14.04-server-cloudimg-amd64-disk1.img",
|
||||
"cdrom_image": "ubuntu-cloud-init-data.iso"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "Ubuntu",
|
||||
"name": "Ubuntu Docker Guest",
|
||||
"category": "guest",
|
||||
"description": "Ubuntu is a Debian-based Linux operating system, with Unity as its default desktop environment. It is based on free software and named after the Southern African philosophy of ubuntu (literally, \"human-ness\"), which often is translated as \"humanity towards others\" or \"the belief in a universal bond of sharing that connects all humanity\".",
|
||||
"vendor_name": "Canonical",
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "Ubuntu",
|
||||
"name": "Ubuntu Desktop Guest",
|
||||
"category": "guest",
|
||||
"description": "Ubuntu is a full-featured Linux operating system which is based on Debian distribution and freely available with both community and professional support, it comes with Unity as its default desktop environment. There are other flavors of Ubuntu available with other desktops as default like Ubuntu Gnome, Lubuntu, Xubuntu, and so on. A tightly-integrated selection of excellent applications is included, and an incredible variety of add-on software is just a few clicks away. A default installation of Ubuntu contains a wide range of software that includes LibreOffice, Firefox, Empathy, Transmission, etc.",
|
||||
"vendor_name": "Canonical Inc.",
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "untangle_1320_x64.iso",
|
||||
"version": "13.2.0",
|
||||
"md5sum": "0ce2293acec0f37f1339e703653727f8",
|
||||
"filesize": 768000000,
|
||||
"download_url": "https://www.untangle.com/get-untangle/"
|
||||
},
|
||||
{
|
||||
"filename": "untangle_1310_x64.iso",
|
||||
"version": "13.1.0",
|
||||
@@ -90,6 +97,13 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "13.2.0",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2",
|
||||
"cdrom_image": "untangle_1320_x64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "13.1.0",
|
||||
"images": {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"product_url": "https://www.microsoft.com/en-us/windows",
|
||||
"registry_version": 4,
|
||||
"status": "stable",
|
||||
"availability": "free-to-try",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "These virtual machines expire after 90 days; i.e. you have to re-create them in your project after this time but you don't have to re-import the appliance.\n\nDefault credentials: IEUser / Passw0rd!",
|
||||
@@ -25,6 +26,13 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "MSEdge-Win10-VMWare-disk1.vmdk",
|
||||
"version": "10 w/ Edge",
|
||||
"md5sum": "fef74c69e1949480d4e2095324a169af",
|
||||
"filesize": 5636608512,
|
||||
"download_url": "https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/"
|
||||
},
|
||||
{
|
||||
"filename": "MSEdge_-_Win10_preview.vmdk",
|
||||
"version": "10 w/ Edge",
|
||||
@@ -71,6 +79,12 @@
|
||||
"versions": [
|
||||
{
|
||||
"name": "10 w/ Edge",
|
||||
"images": {
|
||||
"hda_disk_image": "MSEdge-Win10-VMWare-disk1.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "10 w/ Edge (Preview)",
|
||||
"images": {
|
||||
"hda_disk_image": "MSEdge_-_Win10_preview.vmdk"
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"product_url": "https://www.microsoft.com/en-us/windows",
|
||||
"registry_version": 4,
|
||||
"status": "stable",
|
||||
"availability": "free-to-try",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"symbol": "microsoft.svg",
|
||||
@@ -21,7 +22,8 @@
|
||||
"arch": "x86_64",
|
||||
"console_type": "vnc",
|
||||
"boot_priority": "c",
|
||||
"kvm": "require"
|
||||
"kvm": "require",
|
||||
"options": "-usbdevice tablet"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
|
||||
@@ -555,7 +555,7 @@ class BaseManager:
|
||||
# We store the file under his final name only when the upload is finished
|
||||
tmp_path = path + ".tmp"
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
with open(tmp_path, 'wb+') as f:
|
||||
with open(tmp_path, 'wb') as f:
|
||||
while True:
|
||||
packet = yield from stream.read(4096)
|
||||
if not packet:
|
||||
|
||||
@@ -25,6 +25,7 @@ import asyncio
|
||||
import tempfile
|
||||
import psutil
|
||||
import platform
|
||||
import re
|
||||
|
||||
from gns3server.utils.interfaces import interfaces
|
||||
from ..compute.port_manager import PortManager
|
||||
@@ -598,15 +599,24 @@ class BaseNode:
|
||||
@asyncio.coroutine
|
||||
def _ubridge_apply_filters(self, bridge_name, filters):
|
||||
"""
|
||||
Apply filter like rate limiting
|
||||
Apply packet filters
|
||||
|
||||
:param bridge_name: bridge name in uBridge
|
||||
:param filters: Array of filter dictionnary
|
||||
:param filters: Array of filter dictionary
|
||||
"""
|
||||
yield from self._ubridge_send('bridge reset_packet_filters ' + bridge_name)
|
||||
for filter in self._build_filter_list(filters):
|
||||
cmd = 'bridge add_packet_filter {} {}'.format(bridge_name, filter)
|
||||
yield from self._ubridge_send(cmd)
|
||||
for packet_filter in self._build_filter_list(filters):
|
||||
cmd = 'bridge add_packet_filter {} {}'.format(bridge_name, packet_filter)
|
||||
try:
|
||||
yield from self._ubridge_send(cmd)
|
||||
except UbridgeError as e:
|
||||
match = re.search("Cannot compile filter '(.*)': syntax error", str(e))
|
||||
if match:
|
||||
message = "Warning: ignoring BPF packet filter '{}' due to syntax error".format(self.name, match.group(1))
|
||||
log.warning(message)
|
||||
self.project.emit("log.warning", {"message": message})
|
||||
else:
|
||||
raise
|
||||
|
||||
def _build_filter_list(self, filters):
|
||||
"""
|
||||
|
||||
@@ -99,7 +99,7 @@ class Docker(BaseManager):
|
||||
|
||||
:param method: HTTP method
|
||||
:param path: Endpoint in API
|
||||
:param data: Dictionnary with the body. Will be transformed to a JSON
|
||||
:param data: Dictionary with the body. Will be transformed to a JSON
|
||||
:param params: Parameters added as a query arg
|
||||
"""
|
||||
|
||||
|
||||
@@ -314,7 +314,7 @@ class DockerVM(BaseNode):
|
||||
params["Env"].append("GNS3_VOLUMES={}".format(":".join(self._volumes)))
|
||||
|
||||
if self._environment:
|
||||
for e in self._environment.split("\n"):
|
||||
for e in self._environment.strip().split("\n"):
|
||||
e = e.strip()
|
||||
if not e.startswith("GNS3_"):
|
||||
params["Env"].append(e)
|
||||
@@ -352,7 +352,11 @@ class DockerVM(BaseNode):
|
||||
def start(self):
|
||||
"""Starts this Docker container."""
|
||||
|
||||
state = yield from self._get_container_state()
|
||||
try:
|
||||
state = yield from self._get_container_state()
|
||||
except DockerHttp404Error:
|
||||
raise DockerError("Docker container '{name}' with ID {cid} does not exist or is not ready yet. Please try again in a few seconds.".format(name=self.name,
|
||||
cid=self._cid))
|
||||
if state == "paused":
|
||||
yield from self.unpause()
|
||||
elif state == "running":
|
||||
|
||||
@@ -547,7 +547,7 @@ class Dynamips(BaseManager):
|
||||
content = content.replace('%h', vm.name)
|
||||
f.write(content.encode("utf-8"))
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not create config file {}: {}".format(path, e))
|
||||
raise DynamipsError("Could not create config file '{}': {}".format(path, e))
|
||||
|
||||
return os.path.join("configs", os.path.basename(path))
|
||||
|
||||
|
||||
@@ -260,6 +260,8 @@ class DynamipsHypervisor:
|
||||
# Now retrieve the result
|
||||
data = []
|
||||
buf = ''
|
||||
retries = 0
|
||||
max_retries = 10
|
||||
while True:
|
||||
try:
|
||||
try:
|
||||
@@ -276,8 +278,14 @@ class DynamipsHypervisor:
|
||||
log.warning("Connection reset received while reading Dynamips response: {}".format(e))
|
||||
continue
|
||||
if not chunk:
|
||||
raise DynamipsError("No data returned from {host}:{port}, Dynamips process running: {run}"
|
||||
.format(host=self._host, port=self._port, run=self.is_running()))
|
||||
if retries > max_retries:
|
||||
raise DynamipsError("No data returned from {host}:{port}, Dynamips process running: {run}"
|
||||
.format(host=self._host, port=self._port, run=self.is_running()))
|
||||
else:
|
||||
retries += 1
|
||||
yield from asyncio.sleep(0.1)
|
||||
continue
|
||||
retries = 0
|
||||
buf += chunk.decode("utf-8", errors="ignore")
|
||||
except OSError as e:
|
||||
raise DynamipsError("Could not read response for '{command}' from {host}:{port}: {error}, process running: {run}"
|
||||
|
||||
@@ -283,12 +283,15 @@ class Router(BaseNode):
|
||||
if not self._ghost_flag:
|
||||
self.check_available_ram(self.ram)
|
||||
|
||||
# config paths are relative to the working directory configured on Dynamips hypervisor
|
||||
startup_config_path = os.path.join("configs", "i{}_startup-config.cfg".format(self._dynamips_id))
|
||||
private_config_path = os.path.join("configs", "i{}_private-config.cfg".format(self._dynamips_id))
|
||||
|
||||
if not os.path.exists(private_config_path) or not os.path.getsize(private_config_path):
|
||||
if not os.path.exists(os.path.join(self._working_directory, private_config_path)) or \
|
||||
not os.path.getsize(os.path.join(self._working_directory, private_config_path)):
|
||||
# an empty private-config can prevent a router to boot.
|
||||
private_config_path = ''
|
||||
|
||||
yield from self._hypervisor.send('vm set_config "{name}" "{startup}" "{private}"'.format(
|
||||
name=self._name,
|
||||
startup=startup_config_path,
|
||||
|
||||
@@ -25,6 +25,7 @@ import asyncio
|
||||
from ..base_manager import BaseManager
|
||||
from .iou_error import IOUError
|
||||
from .iou_vm import IOUVM
|
||||
from .utils.application_id import get_next_application_id
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -38,8 +39,7 @@ class IOU(BaseManager):
|
||||
def __init__(self):
|
||||
|
||||
super().__init__()
|
||||
self._free_application_ids = list(range(1, 512))
|
||||
self._used_application_ids = {}
|
||||
self._iou_id_lock = asyncio.Lock()
|
||||
|
||||
@asyncio.coroutine
|
||||
def create_node(self, *args, **kwargs):
|
||||
@@ -49,40 +49,14 @@ class IOU(BaseManager):
|
||||
:returns: IOUVM instance
|
||||
"""
|
||||
|
||||
node = yield from super().create_node(*args, **kwargs)
|
||||
try:
|
||||
self._used_application_ids[node.id] = self._free_application_ids.pop(0)
|
||||
except IndexError:
|
||||
raise IOUError("Cannot create a new IOU VM (limit of 512 VMs reached on this host)")
|
||||
with (yield from self._iou_id_lock):
|
||||
# wait for a node to be completely created before adding a new one
|
||||
# this is important otherwise we allocate the same application ID
|
||||
# when creating multiple IOU node at the same time
|
||||
application_id = get_next_application_id(self.nodes)
|
||||
node = yield from super().create_node(*args, application_id=application_id, **kwargs)
|
||||
return node
|
||||
|
||||
@asyncio.coroutine
|
||||
def close_node(self, node_id, *args, **kwargs):
|
||||
"""
|
||||
Closes an IOU VM.
|
||||
|
||||
:returns: IOUVM instance
|
||||
"""
|
||||
|
||||
node = self.get_node(node_id)
|
||||
if node_id in self._used_application_ids:
|
||||
i = self._used_application_ids[node_id]
|
||||
self._free_application_ids.insert(0, i)
|
||||
del self._used_application_ids[node_id]
|
||||
yield from super().close_node(node_id, *args, **kwargs)
|
||||
return node
|
||||
|
||||
def get_application_id(self, node_id):
|
||||
"""
|
||||
Get an unique application identifier for IOU.
|
||||
|
||||
:param node_id: Node identifier
|
||||
|
||||
:returns: IOU application identifier
|
||||
"""
|
||||
|
||||
return self._used_application_ids.get(node_id, 1)
|
||||
|
||||
@staticmethod
|
||||
def get_legacy_vm_workdir(legacy_vm_id, name):
|
||||
"""
|
||||
|
||||
@@ -65,7 +65,7 @@ class IOUVM(BaseNode):
|
||||
:param console: TCP console port
|
||||
"""
|
||||
|
||||
def __init__(self, name, node_id, project, manager, path=None, console=None):
|
||||
def __init__(self, name, node_id, project, manager, application_id=None, path=None, console=None):
|
||||
|
||||
super().__init__(name, node_id, project, manager, console=console)
|
||||
|
||||
@@ -86,7 +86,7 @@ class IOUVM(BaseNode):
|
||||
self._startup_config = ""
|
||||
self._private_config = ""
|
||||
self._ram = 256 # Megabytes
|
||||
self._application_id = None
|
||||
self._application_id = application_id
|
||||
self._l1_keepalives = False # used to overcome the always-up Ethernet interfaces (not supported by all IOSes).
|
||||
|
||||
def _config(self):
|
||||
@@ -348,14 +348,14 @@ class IOUVM(BaseNode):
|
||||
# reload
|
||||
path = os.path.join(os.path.expanduser("~/"), ".iourc")
|
||||
try:
|
||||
with open(path, "wb+") as f:
|
||||
with open(path, "wb") as f:
|
||||
f.write(value.encode("utf-8"))
|
||||
except OSError as e:
|
||||
raise IOUError("Could not write the iourc file {}: {}".format(path, e))
|
||||
|
||||
path = os.path.join(self.temporary_directory, "iourc")
|
||||
try:
|
||||
with open(path, "wb+") as f:
|
||||
with open(path, "wb") as f:
|
||||
f.write(value.encode("utf-8"))
|
||||
except OSError as e:
|
||||
raise IOUError("Could not write the iourc file {}: {}".format(path, e))
|
||||
@@ -1141,9 +1141,7 @@ class IOUVM(BaseNode):
|
||||
|
||||
:returns: integer between 1 and 512
|
||||
"""
|
||||
if self._application_id is None:
|
||||
#FIXME: is this necessary? application ID is allocated by controller and should not be None
|
||||
return self._manager.get_application_id(self.id)
|
||||
|
||||
return self._application_id
|
||||
|
||||
@application_id.setter
|
||||
|
||||
@@ -24,13 +24,14 @@ log = logging.getLogger(__name__)
|
||||
def get_next_application_id(nodes):
|
||||
"""
|
||||
Calculates free application_id from given nodes
|
||||
|
||||
:param nodes:
|
||||
:raises IOUError when exceeds number
|
||||
:return: integer first free id
|
||||
"""
|
||||
used = set([n.properties.get('application_id') for n in nodes if n.node_type == 'iou'])
|
||||
used = set([n.application_id for n in nodes])
|
||||
pool = set(range(1, 512))
|
||||
try:
|
||||
return (pool - used).pop()
|
||||
except KeyError:
|
||||
raise IOUError("Cannot create a new IOU VM (limit of 512 VMs reached)")
|
||||
raise IOUError("Cannot create a new IOU VM (limit of 512 VMs on one host reached)")
|
||||
@@ -533,7 +533,7 @@ class QemuVM(BaseNode):
|
||||
|
||||
if not mac_address:
|
||||
# use the node UUID to generate a random MAC address
|
||||
self._mac_address = "00:%s:%s:%s:%s:00" % (self.project.id[-4:-2], self.project.id[-2:], self.id[-4:-2], self.id[-2:])
|
||||
self._mac_address = "52:%s:%s:%s:%s:00" % (self.project.id[-4:-2], self.project.id[-2:], self.id[-4:-2], self.id[-2:])
|
||||
else:
|
||||
self._mac_address = mac_address
|
||||
|
||||
|
||||
@@ -397,12 +397,12 @@ class VMware(BaseManager):
|
||||
try:
|
||||
stdout_data, _ = yield from asyncio.wait_for(process.communicate(), timeout=timeout)
|
||||
except asyncio.TimeoutError:
|
||||
raise VMwareError("vmrun has timed out after {} seconds!\nTry to run {} in a terminal to see more informations.\n\nMake sure GNS3 and VMware run under the same user and whitelist vmrun.exe in your antivirus.".format(timeout, command_string))
|
||||
raise VMwareError("vmrun has timed out after {} seconds!\nTry to run {} in a terminal to see more details.\n\nMake sure GNS3 and VMware run under the same user and whitelist vmrun.exe in your antivirus.".format(timeout, command_string))
|
||||
|
||||
if process.returncode:
|
||||
# vmrun print errors on stdout
|
||||
vmrun_error = stdout_data.decode("utf-8", errors="ignore")
|
||||
raise VMwareError("vmrun has returned an error: {}\nTry to run {} in a terminal to see more informations.\nAnd make sure GNS3 and VMware run under the same user.".format(vmrun_error, command_string))
|
||||
raise VMwareError("vmrun has returned an error: {}\nTry to run {} in a terminal to see more details.\nAnd make sure GNS3 and VMware run under the same user.".format(vmrun_error, command_string))
|
||||
|
||||
return stdout_data.decode("utf-8", errors="ignore").splitlines()
|
||||
|
||||
|
||||
@@ -745,7 +745,7 @@ class VMwareVM(BaseNode):
|
||||
"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():
|
||||
elif (yield from 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,
|
||||
|
||||
@@ -82,7 +82,8 @@ class Controller:
|
||||
if appliance.status != 'broken':
|
||||
self._appliance_templates[appliance.id] = appliance
|
||||
except (ValueError, OSError, KeyError) as e:
|
||||
log.warning("Can't load %s: %s", path, str(e))
|
||||
log.warning("Cannot load appliance template file '%s': %s", path, str(e))
|
||||
continue
|
||||
|
||||
self._appliances = {}
|
||||
vms = []
|
||||
@@ -122,13 +123,27 @@ class Controller:
|
||||
for prop in vm.copy():
|
||||
if prop in ["enable_remote_console", "use_ubridge"]:
|
||||
del vm[prop]
|
||||
|
||||
# remove deprecated default_symbol and hover_symbol
|
||||
# and set symbol if not present
|
||||
deprecated = ["default_symbol", "hover_symbol"]
|
||||
if len([prop for prop in vm.keys() if prop in deprecated]) > 0:
|
||||
if "default_symbol" in vm.keys():
|
||||
del vm["default_symbol"]
|
||||
if "hover_symbol" in vm.keys():
|
||||
del vm["hover_symbol"]
|
||||
|
||||
if "symbol" not in vm.keys():
|
||||
vm["symbol"] = ":/symbols/computer.svg"
|
||||
|
||||
vm.setdefault("appliance_id", str(uuid.uuid4()))
|
||||
try:
|
||||
appliance = Appliance(vm["appliance_id"], vm)
|
||||
appliance.__json__() # Check if loaded without error
|
||||
self._appliances[appliance.id] = appliance
|
||||
except KeyError as e:
|
||||
# appliance data is not complete (missing name or type)
|
||||
log.warning("Could not load appliance template {} ('{}'): {}".format(vm["appliance_id"], vm.get("name", "unknown"), e))
|
||||
log.warning("Cannot load appliance template {} ('{}'): missing key {}".format(vm["appliance_id"], vm.get("name", "unknown"), e))
|
||||
continue
|
||||
|
||||
# Add builtins
|
||||
|
||||
@@ -44,7 +44,9 @@ class Appliance:
|
||||
# Version of the gui before 2.1 use linked_base
|
||||
# and the server linked_clone
|
||||
if "linked_base" in self._data:
|
||||
self._data["linked_clone"] = self._data.pop("linked_base")
|
||||
linked_base = self._data.pop("linked_base")
|
||||
if "linked_clone" not in self._data:
|
||||
self._data["linked_clone"] = linked_base
|
||||
if data["node_type"] == "iou" and "image" in data:
|
||||
del self._data["image"]
|
||||
self._builtin = builtin
|
||||
|
||||
@@ -118,7 +118,7 @@ class Drawing:
|
||||
|
||||
file_path = os.path.join(self._project.pictures_directory, filename)
|
||||
if not os.path.exists(file_path):
|
||||
with open(file_path, "wb+") as f:
|
||||
with open(file_path, "wb") as f:
|
||||
f.write(data)
|
||||
value = filename
|
||||
|
||||
|
||||
@@ -64,7 +64,6 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id
|
||||
|
||||
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))]
|
||||
|
||||
for file in files:
|
||||
path = os.path.join(root, file)
|
||||
# Try open the file
|
||||
@@ -162,9 +161,12 @@ 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 not prop.endswith("image"):
|
||||
continue
|
||||
|
||||
if node["node_type"] == "iou":
|
||||
if not prop == "path":
|
||||
continue
|
||||
elif not prop.endswith("image"):
|
||||
continue
|
||||
if value is None or value.strip() == '':
|
||||
continue
|
||||
|
||||
@@ -214,7 +216,6 @@ def _export_local_images(project, image, z):
|
||||
continue
|
||||
|
||||
directory = os.path.split(img_directory)[-1:][0]
|
||||
|
||||
if os.path.exists(image):
|
||||
path = image
|
||||
else:
|
||||
@@ -265,4 +266,3 @@ def _export_remote_images(project, compute_id, image_type, image, project_zipfil
|
||||
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)
|
||||
|
||||
@@ -173,12 +173,16 @@ class Link:
|
||||
self._filters = new_filters
|
||||
if self._created:
|
||||
yield from self.update()
|
||||
self._project.controller.notification.emit("link.updated", self.__json__())
|
||||
self._project.dump()
|
||||
|
||||
@asyncio.coroutine
|
||||
def update_suspend(self, value):
|
||||
if value != self._suspend:
|
||||
self._suspend = value
|
||||
yield from self.update()
|
||||
self._project.controller.notification.emit("link.updated", self.__json__())
|
||||
self._project.dump()
|
||||
|
||||
@property
|
||||
def created(self):
|
||||
@@ -196,6 +200,8 @@ class Link:
|
||||
"""
|
||||
|
||||
port = node.get_port(adapter_number, port_number)
|
||||
if port is None:
|
||||
raise aiohttp.web.HTTPNotFound(text="Port {}/{} for {} not found".format(adapter_number, port_number, node.name))
|
||||
if port.link is not None:
|
||||
raise aiohttp.web.HTTPConflict(text="Port is already used")
|
||||
|
||||
@@ -211,6 +217,8 @@ class Link:
|
||||
|
||||
# Check if user is not connecting serial => ethernet
|
||||
other_port = other_node["node"].get_port(other_node["adapter_number"], other_node["port_number"])
|
||||
if other_port is None:
|
||||
raise aiohttp.web.HTTPNotFound(text="Port {}/{} for {} not found".format(other_node["adapter_number"], other_node["port_number"], other_node["node"].name))
|
||||
if port.link_type != other_port.link_type:
|
||||
raise aiohttp.web.HTTPConflict(text="It's not allowed to connect a {} to a {}".format(other_port.link_type, port.link_type))
|
||||
|
||||
@@ -299,6 +307,12 @@ class Link:
|
||||
Dump a pcap file on disk
|
||||
"""
|
||||
|
||||
if os.path.exists(self.capture_file_path):
|
||||
try:
|
||||
os.remove(self.capture_file_path)
|
||||
except OSError as e:
|
||||
raise aiohttp.web.HTTPConflict(text="Could not delete old capture file '{}': {}".format(self.capture_file_path, e))
|
||||
|
||||
try:
|
||||
stream_content = yield from self.read_pcap_from_source()
|
||||
except aiohttp.web.HTTPException as e:
|
||||
@@ -309,16 +323,19 @@ class Link:
|
||||
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:
|
||||
# We read 1 bytes by 1 otherwise the remaining data is not read if the traffic stops
|
||||
data = yield from stream.read(1)
|
||||
if data:
|
||||
f.write(data)
|
||||
# Flush to disk otherwise the live is not really live
|
||||
f.flush()
|
||||
else:
|
||||
break
|
||||
try:
|
||||
with open(self.capture_file_path, "wb") as f:
|
||||
while self._capturing:
|
||||
# We read 1 bytes by 1 otherwise the remaining data is not read if the traffic stops
|
||||
data = yield from stream.read(1)
|
||||
if data:
|
||||
f.write(data)
|
||||
# Flush to disk otherwise the live is not really live
|
||||
f.flush()
|
||||
else:
|
||||
break
|
||||
except OSError as e:
|
||||
raise aiohttp.web.HTTPConflict(text="Could not write capture file '{}': {}".format(self.capture_file_path, e))
|
||||
|
||||
@asyncio.coroutine
|
||||
def stop_capture(self):
|
||||
|
||||
@@ -574,12 +574,12 @@ class Node:
|
||||
def get_port(self, adapter_number, port_number):
|
||||
"""
|
||||
Return the port for this adapter_number and port_number
|
||||
or raise an HTTPNotFound
|
||||
or returns None if the port is not found
|
||||
"""
|
||||
for port in self.ports:
|
||||
if port.adapter_number == adapter_number and port.port_number == port_number:
|
||||
return port
|
||||
raise aiohttp.web.HTTPNotFound(text="Port {}/{} for {} not found".format(adapter_number, port_number, self.name))
|
||||
return None
|
||||
|
||||
def _list_ports(self):
|
||||
"""
|
||||
|
||||
@@ -39,7 +39,6 @@ from ..utils.asyncio.pool import Pool
|
||||
from ..utils.asyncio import locked_coroutine, asyncio_ensure_future
|
||||
from .export_project import export_project
|
||||
from .import_project import import_project
|
||||
from ..compute.iou.utils.application_id import get_next_application_id
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -86,7 +85,6 @@ class Project:
|
||||
self._show_grid = show_grid
|
||||
self._show_interface_labels = show_interface_labels
|
||||
self._loading = False
|
||||
self._add_node_lock = asyncio.Lock()
|
||||
|
||||
# Disallow overwrite of existing project
|
||||
if project_id is None and path is not None:
|
||||
@@ -440,34 +438,27 @@ class Project:
|
||||
if node_id in self._nodes:
|
||||
return self._nodes[node_id]
|
||||
|
||||
with (yield from self._add_node_lock):
|
||||
# wait for a node to be completely created before adding a new one
|
||||
# this is important otherwise we allocate the same application ID
|
||||
# when creating multiple IOU node at the same time
|
||||
if node_type == "iou" and 'application_id' not in kwargs.keys():
|
||||
kwargs['application_id'] = get_next_application_id(self._nodes.values())
|
||||
node = Node(self, compute, name, node_id=node_id, node_type=node_type, **kwargs)
|
||||
if compute not in self._project_created_on_compute:
|
||||
# For a local server we send the project path
|
||||
if compute.id == "local":
|
||||
yield from compute.post("/projects", data={
|
||||
"name": self._name,
|
||||
"project_id": self._id,
|
||||
"path": self._path
|
||||
})
|
||||
else:
|
||||
yield from compute.post("/projects", data={
|
||||
"name": self._name,
|
||||
"project_id": self._id,
|
||||
})
|
||||
|
||||
node = Node(self, compute, name, node_id=node_id, node_type=node_type, **kwargs)
|
||||
if compute not in self._project_created_on_compute:
|
||||
# For a local server we send the project path
|
||||
if compute.id == "local":
|
||||
yield from compute.post("/projects", data={
|
||||
"name": self._name,
|
||||
"project_id": self._id,
|
||||
"path": self._path
|
||||
})
|
||||
else:
|
||||
yield from compute.post("/projects", data={
|
||||
"name": self._name,
|
||||
"project_id": self._id,
|
||||
})
|
||||
|
||||
self._project_created_on_compute.add(compute)
|
||||
yield from node.create()
|
||||
self._nodes[node.id] = node
|
||||
self.controller.notification.emit("node.created", node.__json__())
|
||||
if dump:
|
||||
self.dump()
|
||||
self._project_created_on_compute.add(compute)
|
||||
yield from node.create()
|
||||
self._nodes[node.id] = node
|
||||
self.controller.notification.emit("node.created", node.__json__())
|
||||
if dump:
|
||||
self.dump()
|
||||
return node
|
||||
|
||||
@locked_coroutine
|
||||
@@ -667,9 +658,12 @@ class Project:
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
zipstream = yield from export_project(self, tmpdir, keep_compute_id=True, allow_all_nodes=True)
|
||||
with open(snapshot.path, "wb+") as f:
|
||||
for data in zipstream:
|
||||
f.write(data)
|
||||
try:
|
||||
with open(snapshot.path, "wb") as f:
|
||||
for data in zipstream:
|
||||
f.write(data)
|
||||
except OSError as e:
|
||||
raise aiohttp.web.HTTPConflict(text="Could not write snapshot file '{}': {}".format(snapshot.path, e))
|
||||
except OSError as e:
|
||||
raise aiohttp.web.HTTPInternalServerError(text="Could not create project directory: {}".format(e))
|
||||
|
||||
@@ -826,8 +820,11 @@ class Project:
|
||||
for node_link in link_data["nodes"]:
|
||||
node = self.get_node(node_link["node_id"])
|
||||
port = node.get_port(node_link["adapter_number"], node_link["port_number"])
|
||||
if port is None:
|
||||
log.warning("Port {}/{} for {} not found".format(node_link["adapter_number"], node_link["port_number"], node.name))
|
||||
continue
|
||||
if port.link is not None:
|
||||
# the node port is already attached to another link
|
||||
log.warning("Port {}/{} is already connected to link ID {}".format(node_link["adapter_number"], node_link["port_number"], port.link.id))
|
||||
continue
|
||||
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:
|
||||
@@ -899,7 +896,7 @@ class Project:
|
||||
try:
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
zipstream = yield from export_project(self, tmpdir, keep_compute_id=True, allow_all_nodes=True)
|
||||
with open(os.path.join(tmpdir, "project.gns3p"), "wb+") as f:
|
||||
with open(os.path.join(tmpdir, "project.gns3p"), "wb") as f:
|
||||
for data in zipstream:
|
||||
f.write(data)
|
||||
with open(os.path.join(tmpdir, "project.gns3p"), "rb") as f:
|
||||
|
||||
@@ -65,6 +65,8 @@ class IOUHandler:
|
||||
|
||||
for name, value in request.json.items():
|
||||
if hasattr(vm, name) and getattr(vm, name) != value:
|
||||
if name == "application_id":
|
||||
continue # we must ignore this to avoid overwriting the application_id allocated by the IOU manager
|
||||
if name == "startup_config_content" and (vm.startup_config_content and len(vm.startup_config_content) > 0):
|
||||
continue
|
||||
if name == "private_config_content" and (vm.private_config_content and len(vm.private_config_content) > 0):
|
||||
@@ -116,6 +118,8 @@ class IOUHandler:
|
||||
|
||||
for name, value in request.json.items():
|
||||
if hasattr(vm, name) and getattr(vm, name) != value:
|
||||
if name == "application_id":
|
||||
continue # we must ignore this to avoid overwriting the application_id allocated by the IOU manager
|
||||
setattr(vm, name, value)
|
||||
|
||||
if vm.use_default_iou_values:
|
||||
|
||||
@@ -19,12 +19,12 @@ import aiohttp
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import psutil
|
||||
import tempfile
|
||||
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.compute.project_manager import ProjectManager
|
||||
from gns3server.compute import MODULES
|
||||
from gns3server.utils.ping_stats import PingStats
|
||||
|
||||
from gns3server.schemas.project import (
|
||||
PROJECT_OBJECT_SCHEMA,
|
||||
@@ -186,11 +186,7 @@ class ProjectHandler:
|
||||
|
||||
:returns: hash
|
||||
"""
|
||||
stats = {}
|
||||
# Non blocking call in order to get cpu usage. First call will return 0
|
||||
stats["cpu_usage_percent"] = psutil.cpu_percent(interval=None)
|
||||
stats["memory_usage_percent"] = psutil.virtual_memory().percent
|
||||
return {"action": "ping", "event": stats}
|
||||
return {"action": "ping", "event": PingStats.get()}
|
||||
|
||||
@Route.get(
|
||||
r"/projects/{project_id}/files",
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import aiohttp
|
||||
from gns3server.web.route import Route
|
||||
from gns3server.controller import Controller
|
||||
|
||||
@@ -62,12 +63,15 @@ class SymbolHandler:
|
||||
def upload(request, response):
|
||||
controller = Controller.instance()
|
||||
path = os.path.join(controller.symbols.symbols_path(), os.path.basename(request.match_info["symbol_id"]))
|
||||
with open(path, 'wb+') as f:
|
||||
while True:
|
||||
packet = yield from request.content.read(512)
|
||||
if not packet:
|
||||
break
|
||||
f.write(packet)
|
||||
try:
|
||||
with open(path, 'wb') as f:
|
||||
while True:
|
||||
packet = yield from request.content.read(512)
|
||||
if not packet:
|
||||
break
|
||||
f.write(packet)
|
||||
except OSError as e:
|
||||
raise aiohttp.web.HTTPConflict(text="Could not write symbol file '{}': {}".format(path, e))
|
||||
# Reset the symbol list
|
||||
controller.symbols.list()
|
||||
response.set_status(204)
|
||||
@@ -17,7 +17,8 @@
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import psutil
|
||||
|
||||
from gns3server.utils.ping_stats import PingStats
|
||||
|
||||
|
||||
class NotificationQueue(asyncio.Queue):
|
||||
@@ -38,24 +39,14 @@ class NotificationQueue(asyncio.Queue):
|
||||
# At first get we return a ping so the client immediately receives data
|
||||
if self._first:
|
||||
self._first = False
|
||||
return ("ping", self._getPing(), {})
|
||||
return ("ping", PingStats.get(), {})
|
||||
|
||||
try:
|
||||
(action, msg, kwargs) = yield from asyncio.wait_for(super().get(), timeout)
|
||||
except asyncio.futures.TimeoutError:
|
||||
return ("ping", self._getPing(), {})
|
||||
return ("ping", PingStats.get(), {})
|
||||
return (action, msg, kwargs)
|
||||
|
||||
def _getPing(self):
|
||||
"""
|
||||
Return the content of the ping notification
|
||||
"""
|
||||
msg = {}
|
||||
# Non blocking call in order to get cpu usage. First call will return 0
|
||||
msg["cpu_usage_percent"] = psutil.cpu_percent(interval=None)
|
||||
msg["memory_usage_percent"] = psutil.virtual_memory().percent
|
||||
return msg
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_json(self, timeout):
|
||||
"""
|
||||
|
||||
+1
-1
@@ -160,7 +160,7 @@ def pid_lock(path):
|
||||
with open(path) as f:
|
||||
try:
|
||||
pid = int(f.read())
|
||||
os.kill(pid, 0) # If the proces is not running kill return an error
|
||||
os.kill(pid, 0) # kill returns an error if the process is not running
|
||||
except (OSError, SystemError, ValueError):
|
||||
pid = None
|
||||
except OSError as e:
|
||||
|
||||
@@ -138,8 +138,14 @@ class Hypervisor(UBridgeHypervisor):
|
||||
match = re.search("ubridge version ([0-9a-z\.]+)", output)
|
||||
if match:
|
||||
self._version = match.group(1)
|
||||
if parse_version(self._version) < parse_version("0.9.12"):
|
||||
raise UbridgeError("uBridge executable version must be >= 0.9.12")
|
||||
if sys.platform.startswith("win") or sys.platform.startswith("darwin"):
|
||||
minimum_required_version = "0.9.12"
|
||||
else:
|
||||
# uBridge version 0.9.14 is required for packet filters
|
||||
# to work for IOU nodes.
|
||||
minimum_required_version = "0.9.14"
|
||||
if parse_version(self._version) < parse_version(minimum_required_version):
|
||||
raise UbridgeError("uBridge executable version must be >= {}".format(minimum_required_version))
|
||||
else:
|
||||
raise UbridgeError("Could not determine uBridge version for {}".format(self._path))
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
|
||||
@@ -214,6 +214,8 @@ class UBridgeHypervisor:
|
||||
# Now retrieve the result
|
||||
data = []
|
||||
buf = ''
|
||||
retries = 0
|
||||
max_retries = 10
|
||||
while True:
|
||||
try:
|
||||
try:
|
||||
@@ -222,9 +224,21 @@ class UBridgeHypervisor:
|
||||
# task has been canceled but continue to read
|
||||
# any remaining data sent by the hypervisor
|
||||
continue
|
||||
except ConnectionResetError as e:
|
||||
# Sometimes WinError 64 (ERROR_NETNAME_DELETED) is returned here on Windows.
|
||||
# These happen if connection reset is received before IOCP could complete
|
||||
# a previous operation. Ignore and try again....
|
||||
log.warning("Connection reset received while reading uBridge response: {}".format(e))
|
||||
continue
|
||||
if not chunk:
|
||||
raise UbridgeError("No data returned from {host}:{port}, uBridge process running: {run}"
|
||||
.format(host=self._host, port=self._port, run=self.is_running()))
|
||||
if retries > max_retries:
|
||||
raise UbridgeError("No data returned from {host}:{port}, uBridge process running: {run}"
|
||||
.format(host=self._host, port=self._port, run=self.is_running()))
|
||||
else:
|
||||
retries += 1
|
||||
yield from asyncio.sleep(0.1)
|
||||
continue
|
||||
retries = 0
|
||||
buf += chunk.decode("utf-8")
|
||||
except OSError as e:
|
||||
raise UbridgeError("Lost communication with {host}:{port} :{error}, uBridge process running: {run}"
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2018 GNS3 Technologies Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import psutil
|
||||
import time
|
||||
|
||||
|
||||
class PingStats:
|
||||
"""
|
||||
Ping messages are regularly sent to the client to keep the connection open.
|
||||
We send with it some information about server load.
|
||||
"""
|
||||
|
||||
_last_measurement = 0.0 # time of last measurement
|
||||
_last_cpu_percent = 0.0 # last cpu_percent
|
||||
_last_mem_percent = 0.0 # last virtual_memory().percent
|
||||
|
||||
@classmethod
|
||||
def get(cls):
|
||||
"""
|
||||
Get ping statistics
|
||||
|
||||
:returns: hash
|
||||
"""
|
||||
stats = {}
|
||||
cur_time = time.time()
|
||||
# minimum interval for getting CPU and memory statistics
|
||||
if cur_time < cls._last_measurement or \
|
||||
cur_time > cls._last_measurement + 1.9:
|
||||
cls._last_measurement = cur_time
|
||||
# Non blocking call to get cpu usage. First call will return 0
|
||||
cls._last_cpu_percent = psutil.cpu_percent(interval=None)
|
||||
cls._last_mem_percent = psutil.virtual_memory().percent
|
||||
stats["cpu_usage_percent"] = cls._last_cpu_percent
|
||||
stats["memory_usage_percent"] = cls._last_mem_percent
|
||||
return stats
|
||||
Reference in new issue
Block a user