Compare commits

..
26 Commits
Author SHA1 Message Date
grossmj 0e95e7e023 Release v2.2.16 2020-11-05 15:38:19 +10:30
grossmj 1748250179 Sync appliance files. 2020-11-05 15:30:21 +10:30
grossmj c8ea22c651 Merge branch 'master' into 2.2 2020-11-05 15:05:05 +10:30
grossmj d16cb5ef89 Option to allocate or not the vCPUs and RAM settings for the GNS3 VM. Fixes https://github.com/GNS3/gns3-gui/issues/3069 2020-11-05 11:13:57 +10:30
piotrpekala7 004acdc271 Release web UI 2.2.16 2020-11-04 12:51:25 +01:00
grossmj e182f53d69 Fix wrong defaults for images_path, configs_path, appliances_path. Fixes #1829 2020-11-04 12:30:23 +10:30
grossmj aef8f0dff3 Use EnvironmentFile for Systemd service. Ref https://github.com/GNS3/gns3-gui/issues/3048 2020-11-02 18:23:41 +10:30
grossmj b6a021dabd Fix SSL support for controller and local compute. Fixes #1826 2020-10-27 23:25:19 +10:30
grossmj 5dab0c2587 Prevent WIC to be added/removed while Dynamips router is running. Fixes https://github.com/GNS3/gns3-gui/issues/3082 2020-10-27 20:08:01 +10:30
grossmj 5d1fdceb98 Fix bug with application id allocation for IOU nodes. Fixes #3079 2020-10-27 19:41:24 +10:30
grossmj 5743d47327 Set ident for merge. 2020-10-24 17:04:42 +10:30
grossmj ca69b01d11 Use origin/3.0 for merge into gh-pages branch. 2020-10-24 17:02:44 +10:30
grossmj dd785b61cf Work directly on gh-pages branch to generate the API documentation. 2020-10-24 16:59:55 +10:30
grossmj 0f154e5f29 Fix invalid syntax for git merge 2020-10-24 16:45:53 +10:30
grossmj f9c4c82da6 Fix merge issues on gh-pages branch, second try. 2020-10-24 16:12:17 +10:30
grossmj 3a136a46a1 Fix merge issues on gh-pages branch 2020-10-24 16:07:48 +10:30
grossmj a6a35e7c43 Fix publish_api_documentation.yml 2020-10-24 15:42:44 +10:30
grossmj 163a867f00 Only automatically build API documentation for 3.0 branch and v3.* tags 2020-10-24 15:24:32 +10:30
grossmj d2b7c9bcbf Do not build API documentation on schedule. 2020-10-24 13:38:32 +10:30
grossmj fb8df1cc6b Fetch all history for all tags and branches in publish_api_documentation.yml 2020-10-24 13:13:19 +10:30
grossmj d063b3e39d Manual trigger API documentation publishing using workflow_dispatch 2020-10-24 13:08:10 +10:30
grossmj 83fbd1f627 Fix GitHub Actions error: A branch or tag with the name '3' could not be found. 2020-10-24 12:16:05 +10:30
grossmj 1aa6fe8535 Add publish_api_documentation.yml to master branch for scheduled event to work. 2020-10-23 23:03:50 +10:30
grossmj 362701f5aa Allow commas in image paths and VM name for Qemu VMs. Fixes https://github.com/GNS3/gns3-gui/issues/3065 2020-10-11 14:02:22 +10:30
grossmj 91244456f5 Handle comma in disk path for Qemu VMs. Fixes https://github.com/GNS3/gns3-gui/issues/3065 2020-10-08 22:09:03 +10:30
grossmj 88ab528977 Development on 2.2.16dev1 2020-10-07 16:30:03 +10:30
32 changed files with 290 additions and 101 deletions

No files matched your search

@@ -0,0 +1,43 @@
name: publish-api-documentation
on:
workflow_dispatch:
push:
tags:
- v3.*
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
ref: "gh-pages"
- uses: actions/setup-python@v2
with:
python-version: 3.6
- name: Merge changes from 3.0 branch
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git merge origin/3.0 -X theirs
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Install GNS3 server
run: |
python setup.py install
- name: Generate the API documentation
run: |
cd scripts
python3 publish_api_documentation.py
- name: Publish the API documentation
run: |
git add docs
git status
git commit -m "Publish API documentation"
git push
+11
View File
@@ -1,5 +1,16 @@
# Change Log
## 2.2.16 05/11/2020
* Option to allocate or not the vCPUs and RAM settings for the GNS3 VM. Fixes https://github.com/GNS3/gns3-gui/issues/3069
* Release Web UI version 2.2.16
* Fix wrong defaults for images_path, configs_path, appliances_path. Fixes #1829
* Use EnvironmentFile for Systemd service. Ref https://github.com/GNS3/gns3-gui/issues/3048
* Fix SSL support for controller and local compute. Fixes #1826
* Prevent WIC to be added/removed while Dynamips router is running. Fixes https://github.com/GNS3/gns3-gui/issues/3082
* Fix bug with application id allocation for IOU nodes. Fixes #3079
* Allow commas in image paths and VM name for Qemu VMs. Fixes https://github.com/GNS3/gns3-gui/issues/3065
## 2.2.15 07/10/2020
* Fix symbol retrieval issue. Ref #1824
+20 -6
View File
@@ -27,10 +27,17 @@
},
"images": [
{
"filename": "vEOS-lab-4.25.0FX-LDP-RSVP.vmdk",
"version": "4.25.0FX",
"md5sum": "b7c2efdbe48301a78f124db989710346",
"filesize": 468647936,
"filename": "vEOS-lab-4.25.0F.vmdk",
"version": "4.25.0F",
"md5sum": "d420763fdf3bc50e7e5b88418bd9d1fd",
"filesize": 468779008,
"download_url": "https://www.arista.com/en/support/software-download"
},
{
"filename": "vEOS-lab-4.24.3M.vmdk",
"version": "4.24.3M",
"md5sum": "0a28e44c7ce4a8965f24a4a463a89b7d",
"filesize": 455213056,
"download_url": "https://www.arista.com/en/support/software-download"
},
{
@@ -204,10 +211,17 @@
],
"versions": [
{
"name": "4.25.0FX",
"name": "4.25.0F",
"images": {
"hda_disk_image": "Aboot-veos-serial-8.0.0.iso",
"hdb_disk_image": "vEOS-lab-4.25.0FX-LDP-RSVP.vmdk"
"hdb_disk_image": "vEOS-lab-4.25.0F.vmdk"
}
},
{
"name": "4.24.3M",
"images": {
"hda_disk_image": "Aboot-veos-serial-8.0.0.iso",
"hdb_disk_image": "vEOS-lab-4.24.3M.vmdk"
}
},
{
+2 -1
View File
@@ -20,7 +20,8 @@
"hda_disk_interface": "virtio",
"arch": "x86_64",
"console_type": "telnet",
"kvm": "require"
"kvm": "require",
"options": "-machine pc-q35-4.2"
},
"images": [
{
@@ -26,6 +26,13 @@
"options": "-nographic"
},
"images": [
{
"filename": "VOSSGNS3.8.2.0.0.qcow2",
"version": "v8.2.0.0",
"md5sum": "9a0cd77c08644abbf3a69771c125c011",
"filesize": 331808768,
"direct_download_url": "https://akamai-ep.extremenetworks.com/Extreme_P/github-en/Virtual_VOSS/VOSSGNS3.8.2.0.0.qcow2"
},
{
"filename": "VOSSGNS3.8.1.5.0.qcow2",
"version": "8.1.5.0",
@@ -56,6 +63,12 @@
}
],
"versions": [
{
"name": "v8.2.0.0",
"images": {
"hda_disk_image": "VOSSGNS3.8.2.0.0.qcow2"
}
},
{
"name": "8.1.5.0",
"images": {
+28
View File
@@ -27,6 +27,20 @@
"options": "-smp 2 -cpu host"
},
"images": [
{
"filename": "BIGIP-16.0.0.1-0.0.3.qcow2",
"version": "16.0.0.1",
"md5sum": "95ff618b7d0b53c4252299cd49b0e564",
"filesize": 5393088512,
"download_url": "https://downloads.f5.com/esd/serveDownload.jsp?path=/big-ip/big-ip_v16.x/16.0.0/english/16.0.0.1_virtual-edition/&sw=BIG-IP&pro=big-ip_v16.x&ver=16.0.0&container=16.0.0.1_Virtual-Edition&file=BIGIP-16.0.0.1-0.0.3.ALL.qcow2.zip"
},
{
"filename": "BIGIP-16.0.0-0.0.12.qcow2",
"version": "16.0.0",
"md5sum": "c49cd2513e386f3259eb0ee6fe3bb502",
"filesize": 5344722944,
"download_url": "https://downloads.f5.com/esd/serveDownload.jsp?path=/big-ip/big-ip_v16.x/16.0.0/english/16.0.0_virtual-edition/&sw=BIG-IP&pro=big-ip_v16.x&ver=16.0.0&container=16.0.0_Virtual-Edition&file=BIGIP-16.0.0-0.0.12.ALL.qcow2.zip"
},
{
"filename": "BIGIP-15.1.0.2-0.0.9.qcow2",
"version": "15.1.0.2",
@@ -163,6 +177,20 @@
}
],
"versions": [
{
"name": "16.0.0.1",
"images": {
"hda_disk_image": "BIGIP-16.0.0.1-0.0.3.qcow2",
"hdb_disk_image": "empty100G.qcow2"
}
},
{
"name": "16.0.0",
"images": {
"hda_disk_image": "BIGIP-16.0.0-0.0.12.qcow2",
"hdb_disk_image": "empty100G.qcow2"
}
},
{
"name": "15.1.0.2",
"images": {
+14 -14
View File
@@ -25,31 +25,31 @@
},
"images": [
{
"filename": "OPNsense-18.1.6-OpenSSL-nano-amd64.img",
"version": "18.1.6",
"md5sum": "042f328380ad0c8008759c43435e8843",
"filesize": 272003136,
"download_url": "https://opnsense.c0urier.net/releases/18.1/"
"filename": "OPNsense-20.7-OpenSSL-nano-amd64.img",
"version": "20.7",
"md5sum": "453e505e9526d4a0a3d5208efdd13b1a",
"filesize": 3221225472,
"download_url": "https://opnsense.c0urier.net/releases/20.7/"
},
{
"filename": "OPNsense-17.7.5-OpenSSL-nano-amd64.img",
"version": "17.7.5",
"md5sum": "6ec5b7f99cc727f904bbf2aaadcab0b8",
"filesize": 237038601,
"download_url": "https://opnsense.c0urier.net/releases/17.7/"
"filename": "OPNsense-19.7-OpenSSL-nano-amd64.img",
"version": "19.7",
"md5sum": "a15a00cfa2de45791d6bc230d8469dc7",
"filesize": 3221225472,
"download_url": "https://opnsense.c0urier.net/releases/19.7/"
}
],
"versions": [
{
"name": "18.1.6",
"name": "20.7",
"images": {
"hda_disk_image": "OPNsense-18.1.6-OpenSSL-nano-amd64.img"
"hda_disk_image": "OPNsense-20.7-OpenSSL-nano-amd64.img"
}
},
{
"name": "17.7.5",
"name": "19.7",
"images": {
"hda_disk_image": "OPNsense-17.7.5-OpenSSL-nano-amd64.img"
"hda_disk_image": "OPNsense-19.7-OpenSSL-nano-amd64.img"
}
}
]
+15 -2
View File
@@ -11,12 +11,12 @@
"status": "stable",
"maintainer": "GNS3 Team",
"maintainer_email": "developers@gns3.net",
"usage": "Credentials: SSH ---> username: root ---> password: 1234 MySQL DB: ---> username: root --> password: tacacs Web interface: ---> username: tacgui ---> password: abc123",
"usage": "Credentials:\nSSH ---> username: root ---> password: 1234\nMySQL DB: ---> username: root --> password: tacacs\nWeb interface: ---> username: tacgui ---> password: abc123\n\nDefault for 0.9.82 or above:\nIP Address: 10.0.0.254\nNetmask: 255.0.0.0\nGateway: 10.0.0.1",
"port_name_format": "Port{port1}",
"qemu": {
"adapter_type": "e1000",
"adapters": 1,
"ram": 1024,
"ram": 4096,
"hda_disk_interface": "ide",
"arch": "x86_64",
"console_type": "telnet",
@@ -24,6 +24,13 @@
"kvm": "allow"
},
"images": [
{
"filename": "tacgui-0.9.82-20201008.qcow2",
"version": "0.9.82",
"md5sum": "dc0c84aa61d8960a23bf3b309a826f3f",
"filesize": 2914844672,
"download_url": "https://drive.google.com/open?id=1tlDSyoD5dAWgJu6I76CgYV7BkwhScWSS"
},
{
"filename": "tac_plus.qcow2",
"version": "201710201114",
@@ -33,6 +40,12 @@
}
],
"versions": [
{
"name": "0.9.82",
"images": {
"hda_disk_image": "tacgui-0.9.82-20201008.qcow2"
}
},
{
"name": "201710201114",
"images": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "Tiny Core Linux",
"category": "guest",
"description": "Core Linux is a smaller variant of Tiny Core without a graphical desktop.\n\nIt's provide a complete Linux system in few MB.",
"description": "Core Linux is a smaller variant of Tiny Core without a graphical desktop.\n\nIt provides a complete Linux system using only a few MiB." ,
"vendor_name": "Team Tiny Core",
"vendor_url": "http://distro.ibiblio.org/tinycorelinux",
"documentation_url": "http://wiki.tinycorelinux.net/",
+13
View File
@@ -25,6 +25,13 @@
"options": "-vga virtio"
},
"images": [
{
"filename": "Ubuntu 20.04 (64bit).vmdk",
"version": "20.04",
"md5sum": "cf619dfe9bb8d89e2b18b067f02e57a0",
"filesize": 6629883904,
"download_url": "http://www.osboxes.org/ubuntu/"
},
{
"filename": "Ubuntu 19.04 (64bit).vmdk",
"version": "19.04",
@@ -55,6 +62,12 @@
}
],
"versions": [
{
"name": "20.04",
"images": {
"hda_disk_image": "Ubuntu 20.04 (64bit).vmdk"
}
},
{
"name": "19.04",
"images": {
+13 -5
View File
@@ -1182,13 +1182,17 @@ class Router(BaseNode):
if not adapter.wic_slot_available(wic_slot_number):
raise DynamipsError("WIC slot {wic_slot_number} is already occupied by another WIC".format(wic_slot_number=wic_slot_number))
if await self.is_running():
raise DynamipsError('WIC "{wic}" cannot be added while router "{name}" is running'.format(wic=wic,
name=self._name))
# Dynamips WICs slot IDs start on a multiple of 16
# WIC1 = 16, WIC2 = 32 and WIC3 = 48
internal_wic_slot_number = 16 * (wic_slot_number + 1)
await self._hypervisor.send('vm slot_add_binding "{name}" {slot_number} {wic_slot_number} {wic}'.format(name=self._name,
slot_number=slot_number,
wic_slot_number=internal_wic_slot_number,
wic=wic))
slot_number=slot_number,
wic_slot_number=internal_wic_slot_number,
wic=wic))
log.info('Router "{name}" [{id}]: {wic} inserted into WIC slot {wic_slot_number}'.format(name=self._name,
id=self._id,
@@ -1217,12 +1221,16 @@ class Router(BaseNode):
if adapter.wic_slot_available(wic_slot_number):
raise DynamipsError("No WIC is installed in WIC slot {wic_slot_number}".format(wic_slot_number=wic_slot_number))
if await self.is_running():
raise DynamipsError('WIC cannot be removed from slot {wic_slot_number} while router "{name}" is running'.format(wic_slot_number=wic_slot_number,
name=self._name))
# Dynamips WICs slot IDs start on a multiple of 16
# WIC1 = 16, WIC2 = 32 and WIC3 = 48
internal_wic_slot_number = 16 * (wic_slot_number + 1)
await self._hypervisor.send('vm slot_remove_binding "{name}" {slot_number} {wic_slot_number}'.format(name=self._name,
slot_number=slot_number,
wic_slot_number=internal_wic_slot_number))
slot_number=slot_number,
wic_slot_number=internal_wic_slot_number))
log.info('Router "{name}" [{id}]: {wic} removed from WIC slot {wic_slot_number}'.format(name=self._name,
id=self._id,
+14 -8
View File
@@ -1691,6 +1691,10 @@ class QemuVM(BaseNode):
else:
disk = disk_image
# From Qemu man page: if the filename contains comma, you must double it
# (for instance, "file=my,,file" to use file "my,file").
disk = disk.replace(",", ",,")
if interface == "sata":
# special case, sata controller doesn't exist in Qemu
options.extend(["-device", 'ahci,id=ahci{}'.format(disk_index)])
@@ -1737,7 +1741,7 @@ class QemuVM(BaseNode):
raise QemuError("cdrom image '{}' is not accessible".format(self._cdrom_image))
if self._hdc_disk_image:
raise QemuError("You cannot use a disk image on hdc disk and a CDROM image at the same time")
options.extend(["-cdrom", self._cdrom_image])
options.extend(["-cdrom", self._cdrom_image.replace(",", ",,")])
return options
def _bios_option(self):
@@ -1749,7 +1753,7 @@ class QemuVM(BaseNode):
raise QemuError("bios image '{}' linked to '{}' is not accessible".format(self._bios_image, os.path.realpath(self._bios_image)))
else:
raise QemuError("bios image '{}' is not accessible".format(self._bios_image))
options.extend(["-bios", self._bios_image])
options.extend(["-bios", self._bios_image.replace(",", ",,")])
return options
def _linux_boot_options(self):
@@ -1761,14 +1765,14 @@ class QemuVM(BaseNode):
raise QemuError("initrd file '{}' linked to '{}' is not accessible".format(self._initrd, os.path.realpath(self._initrd)))
else:
raise QemuError("initrd file '{}' is not accessible".format(self._initrd))
options.extend(["-initrd", self._initrd])
options.extend(["-initrd", self._initrd.replace(",", ",,")])
if self._kernel_image:
if not os.path.isfile(self._kernel_image) or not os.path.exists(self._kernel_image):
if os.path.islink(self._kernel_image):
raise QemuError("kernel image '{}' linked to '{}' is not accessible".format(self._kernel_image, os.path.realpath(self._kernel_image)))
else:
raise QemuError("kernel image '{}' is not accessible".format(self._kernel_image))
options.extend(["-kernel", self._kernel_image])
options.extend(["-kernel", self._kernel_image.replace(",", ",,")])
if self._kernel_command_line:
options.extend(["-append", self._kernel_command_line])
@@ -2008,7 +2012,7 @@ class QemuVM(BaseNode):
log.info('QEMU VM "{name}" [{id}] VM saved state detected (snapshot name: {snapshot})'.format(name=self._name,
id=self.id,
snapshot=snapshot_name))
return ["-loadvm", snapshot_name]
return ["-loadvm", snapshot_name.replace(",", ",,")]
except subprocess.SubprocessError as e:
raise QemuError("Error while looking for the Qemu VM saved state snapshot: {}".format(e))
@@ -2020,16 +2024,18 @@ class QemuVM(BaseNode):
(to be passed to subprocess.Popen())
"""
vm_name = self._name.replace(",", ",,")
project_path = self.project.path.replace(",", ",,")
additional_options = self._options.strip()
additional_options = additional_options.replace("%vm-name%", '"' + self._name.replace('"', '\\"') + '"')
additional_options = additional_options.replace("%vm-name%", '"' + vm_name.replace('"', '\\"') + '"')
additional_options = additional_options.replace("%vm-id%", self._id)
additional_options = additional_options.replace("%project-id%", self.project.id)
additional_options = additional_options.replace("%project-path%", '"' + self.project.path.replace('"', '\\"') + '"')
additional_options = additional_options.replace("%project-path%", '"' + project_path.replace('"', '\\"') + '"')
additional_options = additional_options.replace("%guest-cid%", str(self._guest_cid))
if self._console_type != "none" and self._console:
additional_options = additional_options.replace("%console-port%", str(self._console))
command = [self.qemu_path]
command.extend(["-name", self._name])
command.extend(["-name", vm_name])
command.extend(["-m", "{}M".format(self._ram)])
command.extend(["-smp", "cpus={},sockets=1".format(self._cpus)])
if await self._run_with_hardware_acceleration(self.qemu_path, self._options):
+13 -6
View File
@@ -81,16 +81,23 @@ class Controller:
name = "Main server"
computes = self._load_controller_settings()
from gns3server.web.web_server import WebServer
ssl_context = WebServer.instance(host=host, port=port).ssl_context()
protocol = server_config.get("protocol", "http")
if ssl_context and protocol != "https":
log.warning("Protocol changed to 'https' for local compute because SSL is enabled".format(port))
protocol = "https"
try:
self._local_server = await self.add_compute(compute_id="local",
name=name,
protocol=server_config.get("protocol", "http"),
protocol=protocol,
host=host,
console_host=console_host,
port=port,
user=server_config.get("user", ""),
password=server_config.get("password", ""),
force=True)
force=True,
ssl_context=ssl_context)
except aiohttp.web.HTTPConflict:
log.fatal("Cannot access to the local server, make sure something else is not running on the TCP port {}".format(port))
sys.exit(1)
@@ -266,7 +273,7 @@ class Controller:
"""
server_config = Config.instance().get_section_config("Server")
images_path = os.path.expanduser(server_config.get("images_path", "~/GNS3/projects"))
images_path = os.path.expanduser(server_config.get("images_path", "~/GNS3/images"))
os.makedirs(images_path, exist_ok=True)
return images_path
@@ -276,9 +283,9 @@ class Controller:
"""
server_config = Config.instance().get_section_config("Server")
images_path = os.path.expanduser(server_config.get("configs_path", "~/GNS3/projects"))
os.makedirs(images_path, exist_ok=True)
return images_path
configs_path = os.path.expanduser(server_config.get("configs_path", "~/GNS3/configs"))
os.makedirs(configs_path, exist_ok=True)
return configs_path
async def add_compute(self, compute_id=None, name=None, force=False, connect=True, **kwargs):
"""
+1 -1
View File
@@ -70,7 +70,7 @@ class ApplianceManager:
"""
server_config = Config.instance().get_section_config("Server")
appliances_path = os.path.expanduser(server_config.get("appliances_path", "~/GNS3/projects"))
appliances_path = os.path.expanduser(server_config.get("appliances_path", "~/GNS3/appliances"))
os.makedirs(appliances_path, exist_ok=True)
return appliances_path
+6 -2
View File
@@ -57,7 +57,8 @@ class Compute:
A GNS3 compute.
"""
def __init__(self, compute_id, controller=None, protocol="http", host="localhost", port=3080, user=None, password=None, name=None, console_host=None):
def __init__(self, compute_id, controller=None, protocol="http", host="localhost",
port=3080, user=None, password=None, name=None, console_host=None, ssl_context=None):
self._http_session = None
assert controller is not None
log.info("Create compute %s", compute_id)
@@ -81,6 +82,7 @@ class Compute:
self._cpu_usage_percent = None
self._memory_usage_percent = None
self._last_error = None
self._ssl_context = ssl_context
self._capabilities = {
"version": None,
"node_types": []
@@ -92,7 +94,9 @@ class Compute:
def _session(self):
if self._http_session is None or self._http_session.closed is True:
self._http_session = aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=None, force_close=True))
self._http_session = aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=None,
force_close=True,
ssl_context=self._ssl_context))
return self._http_session
#def __del__(self):
+2
View File
@@ -49,6 +49,7 @@ class GNS3VM:
"headless": False,
"enable": False,
"engine": "vmware",
"allocate_vcpus_ram": True,
"ram": 2048,
"vcpus": 1,
"port": 80,
@@ -311,6 +312,7 @@ class GNS3VM:
if self._settings["vmname"] is None:
return
log.info("Start the GNS3 VM")
engine.allocate_vcpus_ram = self._settings["allocate_vcpus_ram"]
engine.vmname = self._settings["vmname"]
engine.ram = self._settings["ram"]
engine.vcpus = self._settings["vcpus"]
@@ -30,6 +30,7 @@ class BaseGNS3VM:
self._ip_address = None
self._port = 80 # value not used, will be overwritten
self._headless = False
self._allocate_vcpus_ram = True
self._vcpus = 1
self._ram = 1024
self._user = ""
@@ -203,6 +204,26 @@ class BaseGNS3VM:
self._headless = value
@property
def allocate_vcpus_ram(self):
"""
Returns whether VCPUs and RAM settings should be configured for the GNS3 VM.
:returns: boolean
"""
return self._allocate_vcpus_ram
@allocate_vcpus_ram.setter
def allocate_vcpus_ram(self, value):
"""
Sets whether VCPUs and RAM settings should be configured for the GNS3 VM.
:param value: boolean
"""
self._allocate_vcpus_ram = value
@property
def vcpus(self):
"""
@@ -251,9 +251,10 @@ class HyperVGNS3VM(BaseGNS3VM):
raise GNS3VMError("Could not find Hyper-V VM {}".format(self.vmname))
if not self._is_running():
log.info("Update GNS3 VM settings (CPU and RAM)")
# set the number of vCPUs and amount of RAM
self._set_vcpus_ram(self.vcpus, self.ram)
if self.allocate_vcpus_ram:
log.info("Update GNS3 VM settings (CPU and RAM)")
# set the number of vCPUs and amount of RAM
self._set_vcpus_ram(self.vcpus, self.ram)
# start the VM
try:
@@ -15,8 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import asyncio
from .base_gns3_vm import BaseGNS3VM
from .gns3_vm_error import GNS3VMError
@@ -259,9 +259,12 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
log.info('"{}" state is {}'.format(self._vmname, vm_state))
if vm_state == "poweroff":
log.info("Update GNS3 VM settings (CPU, RAM and Hardware Virtualization)")
await self.set_vcpus(self.vcpus)
await self.set_ram(self.ram)
if self.allocate_vcpus_ram:
log.info("Update GNS3 VM vCPUs and RAM settings")
await self.set_vcpus(self.vcpus)
await self.set_ram(self.ram)
log.info("Update GNS3 VM Hardware Virtualization setting")
await self.enable_nested_hw_virt()
if vm_state in ("poweroff", "saved"):
@@ -148,9 +148,12 @@ class VMwareGNS3VM(BaseGNS3VM):
except VMwareError as e:
raise GNS3VMError("Could not list VMware VMs: {}".format(str(e)))
if not running:
log.info("Update GNS3 VM settings (CPU, RAM and Hardware Virtualization)")
# set the number of vCPUs and amount of RAM
await self._set_vcpus_ram(self.vcpus, self.ram)
if self.allocate_vcpus_ram:
log.info("Update GNS3 VM vCPUs and RAM settings")
await self._set_vcpus_ram(self.vcpus, self.ram)
log.info("Update GNS3 VM Hardware Virtualization setting")
await self._set_extra_options()
# start the VM
+16 -2
View File
@@ -174,6 +174,7 @@ class Project:
self._links = {}
self._drawings = {}
self._snapshots = {}
self._computes = []
# List the available snapshots
snapshot_dir = os.path.join(self.path, "snapshots")
@@ -564,6 +565,9 @@ class Project:
if node_id in self._nodes:
return self._nodes[node_id]
if compute.id not in self._computes:
self._computes.append(compute.id)
if node_type == "iou":
async with self._iou_id_lock:
# wait for a IOU node to be completely created before adding a new one
@@ -571,10 +575,10 @@ class Project:
# to generate MAC addresses) when creating multiple IOU node at the same time
if "properties" in kwargs.keys():
# allocate a new application id for nodes loaded from the project
kwargs.get("properties")["application_id"] = get_next_application_id(self._controller.projects, compute)
kwargs.get("properties")["application_id"] = get_next_application_id(self._controller.projects, self._computes)
elif "application_id" not in kwargs.keys() and not kwargs.get("properties"):
# allocate a new application id for nodes added to the project
kwargs["application_id"] = get_next_application_id(self._controller.projects, compute)
kwargs["application_id"] = get_next_application_id(self._controller.projects, self._computes)
node = await self._create_node(compute, name, node_id, node_type, **kwargs)
else:
node = await self._create_node(compute, name, node_id, node_type, **kwargs)
@@ -604,6 +608,8 @@ class Project:
self.remove_allocated_node_name(node.name)
del self._nodes[node.id]
await node.destroy()
# refresh the compute IDs list
self._computes = [n.compute.id for n in self.nodes.values()]
self.dump()
self.emit_notification("node.deleted", node.__json__())
@@ -931,6 +937,14 @@ class Project:
topology = project_data["topology"]
for compute in topology.get("computes", []):
await self.controller.add_compute(**compute)
# Get all compute used in the project
# used to allocate application IDs for IOU nodes.
for node in topology.get("nodes", []):
compute_id = node.get("compute_id")
if compute_id not in self._computes:
self._computes.append(compute_id)
for node in topology.get("nodes", []):
compute = self.controller.get_compute(node.pop("compute_id"))
name = node.pop("name")
+1 -1
View File
@@ -58,7 +58,7 @@ class CrashReport:
Report crash to a third party service
"""
DSN = "https://c0b6ce011d024391831923745a47c33f:459ea5884d3944f092b02e4183cb6d52@o19455.ingest.sentry.io/38482"
DSN = "https://026410fd151843438d078e604f2e4455:1792bf69988342c7b44f8a69ae0cad6f@o19455.ingest.sentry.io/38482"
_instance = None
def __init__(self):
+4
View File
@@ -41,6 +41,10 @@ GNS3VM_SETTINGS_SCHEMA = {
"description": "The engine to use for the VM. Null to disable",
"enum": ["vmware", "virtualbox", None]
},
"allocate_vcpus_ram": {
"description": "Allocate vCPUS and RAM settings",
"type": "boolean"
},
"vcpus": {
"description": "Number of vCPUS affected to the VM",
"type": "integer"
@@ -418,31 +418,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
angular2-hotkeys
MIT
The MIT License (MIT)
Copyright (c) 2016 Nick Richardson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
angular2-indexeddb
MIT
The MIT License (MIT)
+1 -1
View File
@@ -48,5 +48,5 @@
gtag('config', 'G-5D6FZL9923');
</script>
<script src="runtime.acf0dec4155e77772545.js" defer></script><script src="polyfills-es5.81e70f503de320d59b44.js" nomodule defer></script><script src="polyfills.7ae454d57e44d75e5d10.js" defer></script><script src="main.b8ab802a67c1c69cf879.js" defer></script></body>
<script src="runtime.acf0dec4155e77772545.js" defer></script><script src="polyfills-es5.81e70f503de320d59b44.js" nomodule defer></script><script src="polyfills.7ae454d57e44d75e5d10.js" defer></script><script src="main.8367ffc0bf45ea7cf3c7.js" defer></script></body>
</html>
@@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[1],{"+/L5":function(e,t,n){var i=n("t1UP").isCustomProperty,r=n("vd7W").TYPE,o=n("4njK").mode,a=r.Ident,s=r.Hash,c=r.Colon,l=r.Semicolon,u=r.Delim;function h(e){return this.Raw(e,o.exclamationMarkOrSemicolon,!0)}function d(e){return this.Raw(e,o.exclamationMarkOrSemicolon,!1)}function f(){var e=this.scanner.tokenIndex,t=this.Value();return"Raw"!==t.type&&!1===this.scanner.eof&&this.scanner.tokenType!==l&&!1===this.scanner.isDelim(33)&&!1===this.scanner.isBalanceEdge(e)&&this.error(),t}function p(){var e=this.scanner.tokenStart;if(this.scanner.tokenType===u)switch(this.scanner.source.charCodeAt(this.scanner.tokenStart)){case 42:case 36:case 43:case 35:case 38:this.scanner.next();break;case 47:this.scanner.next(),this.scanner.isDelim(47)&&this.scanner.next()}return this.eat(this.scanner.tokenType===s?s:a),this.scanner.substrToCursor(e)}function m(){this.eat(u),this.scanner.skipSC();var e=this.consume(a);return"important"===e||e}e.exports={name:"Declaration",structure:{important:[Boolean,String],property:String,value:["Value","Raw"]},parse:function(){var e,t=this.scanner.tokenStart,n=this.scanner.tokenIndex,r=p.call(this),o=i(r),a=o?this.parseCustomProperty:this.parseValue,s=o?d:h,u=!1;return this.scanner.skipSC(),this.eat(c),o||this.scanner.skipSC(),e=a?this.parseWithFallback(f,s):s.call(this,this.scanner.tokenIndex),this.scanner.isDelim(33)&&(u=m.call(this),this.scanner.skipSC()),!1===this.scanner.eof&&this.scanner.tokenType!==l&&!1===this.scanner.isBalanceEdge(n)&&this.error(),{type:"Declaration",loc:this.getLocation(t,this.scanner.tokenStart),important:u,property:r,value:e}},generate:function(e){this.chunk(e.property),this.chunk(":"),this.node(e.value),e.important&&this.chunk(!0===e.important?"!important":"!"+e.important)},walkContext:"declaration"}},"+4/i":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=n("qCKp"),r=n("odkN");i.Observable.prototype.let=r.letProto,i.Observable.prototype.letBind=r.letProto},"+Kd2":function(e,t,n){var i=n("vd7W").TYPE,r=n("4njK").mode,o=i.Comma;e.exports=function(){var e=this.createList();return this.scanner.skipSC(),e.push(this.Identifier()),this.scanner.skipSC(),this.scanner.tokenType===o&&(e.push(this.Operator()),e.push(this.parseCustomProperty?this.Value(null):this.Raw(this.scanner.tokenIndex,r.exclamationMarkOrSemicolon,!1))),e}},"+oeQ":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=n("qCKp"),r=n("H+DX");i.Observable.prototype.observeOn=r.observeOn},"+psR":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=n("qCKp"),r=n("16Oq");i.Observable.prototype.retry=r.retry},"+qxJ":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=n("qCKp"),r=n("GsYY");i.Observable.prototype.distinctUntilChanged=r.distinctUntilChanged},"+v8i":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=n("qCKp");i.Observable.concat=i.concat},"/+5V":function(e,t){function n(e){function t(e){return null!==e&&("Type"===e.type||"Property"===e.type||"Keyword"===e.type)}var n=null;return null!==this.matched&&function i(r){if(Array.isArray(r.match)){for(var o=0;o<r.match.length;o++)if(i(r.match[o]))return t(r.syntax)&&n.unshift(r.syntax),!0}else if(r.node===e)return n=t(r.syntax)?[r.syntax]:[],!0;return!1}(this.matched),n}function i(e,t,i){var r=n.call(e,t);return null!==r&&r.some(i)}e.exports={getTrace:n,isType:function(e,t){return i(this,e,(function(e){return"Type"===e.type&&e.name===t}))},isProperty:function(e,t){return i(this,e,(function(e){return"Property"===e.type&&e.name===t}))},isKeyword:function(e){return i(this,e,(function(e){return"Keyword"===e.type}))}}},"/BcF":function(e,t){e.exports={name:"Selector",structure:{children:[["TypeSelector","IdSelector","ClassSelector","AttributeSelector","PseudoClassSelector","PseudoElementSelector","Combinator","WhiteSpace"]]},parse:function(){var e=this.readSequence(this.scope.Selector);return null===this.getFirstListNode(e)&&this.error("Selector is expected"),{type:"Selector",loc:this.getLocationFromList(e),children:e}},generate:function(e){this.children(e)}}},"/POA":function(e,t,n){window,e.exports=function(e){var t={};function n(i){if(t[i])return t[i].exports;var r=t[i]={i:i,l:!1,exports:{}};return e[i].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(i,r,(function(t){return e[t]}).bind(null,r));return i},n.n=function(e){var t=e&&e.__esModuleLine truncated
@@ -1 +0,0 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[1],{"+/L5":function(e,t,n){var i=n("t1UP").isCustomProperty,r=n("vd7W").TYPE,o=n("4njK").mode,a=r.Ident,s=r.Hash,c=r.Colon,l=r.Semicolon,u=r.Delim;function h(e){return this.Raw(e,o.exclamationMarkOrSemicolon,!0)}function d(e){return this.Raw(e,o.exclamationMarkOrSemicolon,!1)}function f(){var e=this.scanner.tokenIndex,t=this.Value();return"Raw"!==t.type&&!1===this.scanner.eof&&this.scanner.tokenType!==l&&!1===this.scanner.isDelim(33)&&!1===this.scanner.isBalanceEdge(e)&&this.error(),t}function p(){var e=this.scanner.tokenStart;if(this.scanner.tokenType===u)switch(this.scanner.source.charCodeAt(this.scanner.tokenStart)){case 42:case 36:case 43:case 35:case 38:this.scanner.next();break;case 47:this.scanner.next(),this.scanner.isDelim(47)&&this.scanner.next()}return this.eat(this.scanner.tokenType===s?s:a),this.scanner.substrToCursor(e)}function m(){this.eat(u),this.scanner.skipSC();var e=this.consume(a);return"important"===e||e}e.exports={name:"Declaration",structure:{important:[Boolean,String],property:String,value:["Value","Raw"]},parse:function(){var e,t=this.scanner.tokenStart,n=this.scanner.tokenIndex,r=p.call(this),o=i(r),a=o?this.parseCustomProperty:this.parseValue,s=o?d:h,u=!1;return this.scanner.skipSC(),this.eat(c),o||this.scanner.skipSC(),e=a?this.parseWithFallback(f,s):s.call(this,this.scanner.tokenIndex),this.scanner.isDelim(33)&&(u=m.call(this),this.scanner.skipSC()),!1===this.scanner.eof&&this.scanner.tokenType!==l&&!1===this.scanner.isBalanceEdge(n)&&this.error(),{type:"Declaration",loc:this.getLocation(t,this.scanner.tokenStart),important:u,property:r,value:e}},generate:function(e){this.chunk(e.property),this.chunk(":"),this.node(e.value),e.important&&this.chunk(!0===e.important?"!important":"!"+e.important)},walkContext:"declaration"}},"+4/i":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=n("qCKp"),r=n("odkN");i.Observable.prototype.let=r.letProto,i.Observable.prototype.letBind=r.letProto},"+Kd2":function(e,t,n){var i=n("vd7W").TYPE,r=n("4njK").mode,o=i.Comma;e.exports=function(){var e=this.createList();return this.scanner.skipSC(),e.push(this.Identifier()),this.scanner.skipSC(),this.scanner.tokenType===o&&(e.push(this.Operator()),e.push(this.parseCustomProperty?this.Value(null):this.Raw(this.scanner.tokenIndex,r.exclamationMarkOrSemicolon,!1))),e}},"+oeQ":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=n("qCKp"),r=n("H+DX");i.Observable.prototype.observeOn=r.observeOn},"+psR":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=n("qCKp"),r=n("16Oq");i.Observable.prototype.retry=r.retry},"+qxJ":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=n("qCKp"),r=n("GsYY");i.Observable.prototype.distinctUntilChanged=r.distinctUntilChanged},"+v8i":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=n("qCKp");i.Observable.concat=i.concat},"/+5V":function(e,t){function n(e){function t(e){return null!==e&&("Type"===e.type||"Property"===e.type||"Keyword"===e.type)}var n=null;return null!==this.matched&&function i(r){if(Array.isArray(r.match)){for(var o=0;o<r.match.length;o++)if(i(r.match[o]))return t(r.syntax)&&n.unshift(r.syntax),!0}else if(r.node===e)return n=t(r.syntax)?[r.syntax]:[],!0;return!1}(this.matched),n}function i(e,t,i){var r=n.call(e,t);return null!==r&&r.some(i)}e.exports={getTrace:n,isType:function(e,t){return i(this,e,(function(e){return"Type"===e.type&&e.name===t}))},isProperty:function(e,t){return i(this,e,(function(e){return"Property"===e.type&&e.name===t}))},isKeyword:function(e){return i(this,e,(function(e){return"Keyword"===e.type}))}}},"/BcF":function(e,t){e.exports={name:"Selector",structure:{children:[["TypeSelector","IdSelector","ClassSelector","AttributeSelector","PseudoClassSelector","PseudoElementSelector","Combinator","WhiteSpace"]]},parse:function(){var e=this.readSequence(this.scope.Selector);return null===this.getFirstListNode(e)&&this.error("Selector is expected"),{type:"Selector",loc:this.getLocationFromList(e),children:e}},generate:function(e){this.children(e)}}},"/POA":function(e,t,n){window,e.exports=function(e){var t={};function n(i){if(t[i])return t[i].exports;var r=t[i]={i:i,l:!1,exports:{}};return e[i].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(i,r,(function(t){return e[t]}).bind(null,r));return i},n.n=function(e){var t=e&&e.__esModuleLine truncated
+8 -7
View File
@@ -21,26 +21,27 @@ import logging
log = logging.getLogger(__name__)
def get_next_application_id(projects, compute):
def get_next_application_id(projects, computes):
"""
Calculates free application_id from given nodes
:param projects: all projects managed by controller
:param compute: Compute instance
:param computes: all computes used by the project
:raises HTTPConflict when exceeds number
:return: integer first free id
"""
nodes = []
# look for application id for in all nodes across all opened projects that share the same compute
# look for application id for in all nodes across all opened projects that share the same computes
for project in projects.values():
if project.status == "opened" and compute in project.computes:
if project.status == "opened":
nodes.extend(list(project.nodes.values()))
used = set([n.properties["application_id"] for n in nodes if n.node_type == "iou"])
used = set([n.properties["application_id"] for n in nodes if n.node_type == "iou" and n.compute.id in computes])
pool = set(range(1, 512))
try:
return (pool - used).pop()
application_id = (pool - used).pop()
return application_id
except KeyError:
raise aiohttp.web.HTTPConflict(text="Cannot create a new IOU node (limit of 512 nodes across all opened projects using compute {} reached".format(compute.name))
raise aiohttp.web.HTTPConflict(text="Cannot create a new IOU node (limit of 512 nodes across all opened projects using the same computes)")
+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.2.15"
__version_info__ = (2, 2, 15, 0)
__version__ = "2.2.16"
__version_info__ = (2, 2, 16, 0)
if "dev" in __version__:
try:
+11 -5
View File
@@ -64,6 +64,7 @@ class WebServer:
self._start_time = time.time()
self._running = False
self._closing = False
self._ssl_context = None
@staticmethod
def instance(host=None, port=None):
@@ -88,7 +89,6 @@ class WebServer:
return False
return True
async def reload_server(self):
"""
Reload the server.
@@ -96,7 +96,6 @@ class WebServer:
await Controller.instance().reload()
async def shutdown_server(self):
"""
Cleanly shutdown the server.
@@ -147,6 +146,13 @@ class WebServer:
self._loop.stop()
def ssl_context(self):
"""
Returns the SSL context for the server.
"""
return self._ssl_context
def _signal_handling(self):
def signal_handler(signame, *args):
@@ -255,12 +261,12 @@ class WebServer:
server_config = Config.instance().get_section_config("Server")
ssl_context = None
self._ssl_context = None
if server_config.getboolean("ssl"):
if sys.platform.startswith("win"):
log.critical("SSL mode is not supported on Windows")
raise SystemExit
ssl_context = self._create_ssl_context(server_config)
self._ssl_context = self._create_ssl_context(server_config)
self._loop = asyncio.get_event_loop()
@@ -307,7 +313,7 @@ class WebServer:
log.info("Starting server on {}:{}".format(self._host, self._port))
self._handler = self._app.make_handler()
if self._run_application(self._handler, ssl_context) is False:
if self._run_application(self._handler, self._ssl_context) is False:
self._loop.stop()
sys.exit(1)
+1 -1
View File
@@ -260,7 +260,7 @@ Conflicts=shutdown.target
User=gns3
Group=gns3
PermissionsStartOnly=true
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
EnvironmentFile=/etc/environment
ExecStartPre=/bin/mkdir -p /var/log/gns3 /var/run/gns3
ExecStartPre=/bin/chown -R gns3:gns3 /var/log/gns3 /var/run/gns3
ExecStart=/usr/bin/gns3server --log /var/log/gns3/gns3.log