Merge pull request #2238 from GNS3/release-v2.2.40

Release v2.2.40
This commit is contained in:
Jeremy Grossmann 2023-06-06 12:41:40 +09:30 committed by GitHub
commit 4bf7838543
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 241 additions and 140 deletions

View File

@ -1,5 +1,16 @@
# Change Log
## 2.2.40 06/06/2023
* qemu : with network adapter_type equal to "virtio-net-pci", fix the speed to 10000 and duplex to full. The values are actually fake. (https://github.com/GNS3/gns3-gui/issues/3476)
* Parse name for request to node creation from template
* Remove Xvfb + x11vnc support
* Require a Host-Only Network to start the VirtualBox GNS3 VM on macOS with VirtualBox 7
* Properly catch aiohttp client exception. Ref #2228
* Catch ConnectionResetError when waiting for the wrap console
* Fix open IPv6 address for HTTP consoles on controller. Fixes https://github.com/GNS3/gns3-gui/issues/3448
* Use proc.communicate() when checking for subprocess output As recommended in https://docs.python.org/3/library/asyncio-subprocess.html#asyncio.subprocess.Process.stderr
## 2.2.39 08/05/2023
* Install web-ui v2.2.39

View File

@ -37,7 +37,8 @@
"version": "1.0",
"md5sum": "72fb52af76e9561d125dd99224e2c1d1",
"filesize": 374784,
"download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/AlmaLinux/almalinux-cloud-init-data.iso"
"download_url": "https://github.com/GNS3/gns3-registry/tree/master/cloud-init/AlmaLinux",
"direct_download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/AlmaLinux/almalinux-cloud-init-data.iso"
}
],
"versions": [

View File

@ -32,6 +32,13 @@
"process_priority": "normal"
},
"images": [
{
"filename": "arubaoscx-disk-image-genericx86-p4-20230531220439.vmdk",
"version": "10.12.0006",
"md5sum": "c4f80fecd02ef93b431b75dd610e0063",
"filesize": 384638464,
"download_url": "https://asp.arubanetworks.com/"
},
{
"filename": "arubaoscx-disk-image-genericx86-p4-20221130174651.vmdk",
"version": "10.11.0001",
@ -111,6 +118,12 @@
}
],
"versions": [
{
"name": "10.12.0006",
"images": {
"hda_disk_image": "arubaoscx-disk-image-genericx86-p4-20230531220439.vmdk"
}
},
{
"name": "10.11.0001",
"images": {

View File

@ -26,33 +26,37 @@
"options": "-nographic"
},
"images": [
{
"filename": "CentOS-8-GenericCloud-8.4.2105-20210603.0.x86_64.qcow2",
"version": "8.4 (2105)",
"md5sum": "032eed270415526546eac07628905a62",
"filesize": 1309652992,
"download_url": "https://cloud.centos.org/centos/8/x86_64/images",
"direct_download_url": "https://cloud.centos.org/centos/8/x86_64/images/CentOS-8-GenericCloud-8.4.2105-20210603.0.x86_64.qcow2"
},
{
"filename": "CentOS-7-x86_64-GenericCloud-2111.qcow2",
"version": "7 (2111)",
"md5sum": "730b8662695831670721c8245be61dac",
"filesize": 897384448,
"download_url": "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-2111.qcow2"
"download_url": "https://cloud.centos.org/centos/7/images",
"direct_download_url": "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-2111.qcow2"
},
{
"filename": "CentOS-7-x86_64-GenericCloud-1809.qcow2",
"version": "7 (1809)",
"md5sum": "da79108d1324b27bd1759362b82fbe40",
"filesize": 914948096,
"download_url": "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1809.qcow2"
},
{
"filename": "CentOS-8-GenericCloud-8.4.2105-20210603.0.x86_64.qcow2",
"version": "8.4 (2105)",
"md5sum": "032eed270415526546eac07628905a62",
"filesize": 1309652992,
"download_url": "https://cloud.centos.org/centos/8/x86_64/images/CentOS-8-GenericCloud-8.4.2105-20210603.0.x86_64.qcow2"
"download_url": "https://cloud.centos.org/centos/7/images",
"direct_download_url": "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1809.qcow2"
},
{
"filename": "centos-cloud-init-data.iso",
"version": "1.0",
"md5sum": "15ca60c12db6d13b8eeae1a19613fd6e",
"filesize": 378880,
"download_url": "https://github.com/asenci/gns3-centos-cloud-init-data/raw/master/centos-cloud-init-data.iso"
"version": "1.1",
"md5sum": "59ea8223fd659d8bce9081ff175912e9",
"filesize": 374784,
"download_url": "https://github.com/GNS3/gns3-registry/tree/master/cloud-init/centos-cloud",
"direct_download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/centos-cloud/centos-cloud-init-data.iso"
}
],
"versions": [

View File

@ -44,7 +44,8 @@
"version": "1.0",
"md5sum": "43f6bf70c178a9d3c270b5c24971e578",
"filesize": 374784,
"download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/Debian/debian-cloud-init-data.iso"
"download_url": "https://github.com/GNS3/gns3-registry/tree/master/cloud-init/Debian",
"direct_download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/Debian/debian-cloud-init-data.iso"
}
],
"versions": [

View File

@ -31,14 +31,16 @@
"version": "35-1.2",
"md5sum": "cfa9cdcfb946e5f4cf9dd4d7906008d0",
"filesize": 376897536,
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/35/Cloud/x86_64/images/Fedora-Cloud-Base-35-1.2.x86_64.qcow2"
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/35/Cloud/x86_64/images",
"direct_download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/35/Cloud/x86_64/images/Fedora-Cloud-Base-35-1.2.x86_64.qcow2"
},
{
"filename": "fedora-cloud-init-data.iso",
"version": "1.0",
"md5sum": "3d0d6391d3f5ece1180c70b9667c4dca",
"filesize": 374784,
"download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/fedora-cloud/fedora-cloud-init-data.iso"
"download_url": "https://github.com/GNS3/gns3-registry/tree/master/cloud-init/fedora-cloud",
"direct_download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/fedora-cloud/fedora-cloud-init-data.iso"
}
],
"versions": [

View File

@ -0,0 +1,19 @@
{
"appliance_id": "b770027f-1822-4ab6-b2f9-73336ca0983d",
"name": "Mikrotik WinBox",
"category": "guest",
"description": "Mikrotik's WinBox router management software for GNS3",
"vendor_name": "Mikrotik",
"vendor_url": "https://mikrotik.com",
"product_name": "Mikrotik WinBox",
"registry_version": 4,
"status": "stable",
"availability": "free",
"maintainer": "Alexander Horner",
"maintainer_email": "contact@alexhorner.cc",
"docker": {
"adapters": 1,
"image": "gns3/mikrotik-winbox",
"console_type": "vnc"
}
}

View File

@ -14,7 +14,7 @@
"usage": "In the web interface login as admin/admin\n\nPersistent configuration:\n- Add \"/var/lib/redis\" as an additional persistent directory.\n- Use \"redis-cli save\" in an auxiliary console to save the configuration.",
"docker": {
"adapters": 1,
"image": "ntop/ntopng:latest",
"image": "ntop/ntopng:stable",
"start_command": "--dns-mode 2 --interface eth0",
"console_type": "http",
"console_http_port": 3000,

View File

@ -0,0 +1,70 @@
{
"appliance_id": "88e67f45-e0de-4e5e-9f36-2dc83e4a6c60",
"name": "Oracle Linux Cloud Guest",
"category": "guest",
"description": "A highly performant and secure operating environment, Oracle Linux delivers virtualization, management, automation, and cloud native computing tools, along with the operating system, in a single, easy-to-manage support offering. Oracle Linux provides a 100% application binary compatible alternative to Red Hat Enterprise Linux and CentOS Linux and is supported across both hybrid and multicloud environments.",
"vendor_name": "Oracle Corporation",
"vendor_url": "https://www.oracle.com",
"documentation_url": "https://docs.oracle.com/en-us/iaas/images/",
"product_name": "Oracle Linux Cloud Guest",
"product_url": "https://www.oracle.com/au/linux/",
"registry_version": 4,
"status": "stable",
"maintainer": "GNS3 Team",
"maintainer_email": "developers@gns3.net",
"usage": "Username: oracle\nPassword: oracle",
"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": "-cpu host -nographic"
},
"images": [
{
"filename": "OL9U1_x86_64-kvm-b158.qcow",
"version": "9.1",
"md5sum": "9f32851b96fc38191892197fa11f7435",
"filesize": 539033600,
"download_url": "https://yum.oracle.com/oracle-linux-templates.html",
"direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL9/u1/x86_64/OL9U1_x86_64-kvm-b158.qcow"
},
{
"filename": "OL8U7_x86_64-kvm-b148.qcow",
"version": "8.7",
"md5sum": "962cdde7e810888b9914e937222f687f",
"filesize": 913965056,
"download_url": "https://yum.oracle.com/oracle-linux-templates.html",
"direct_download_url": "https://yum.oracle.com/templates/OracleLinux/OL8/u7/x86_64/OL8U7_x86_64-kvm-b148.qcow"
},
{
"filename": "oracle-cloud-init-data.iso",
"version": "1.1",
"md5sum": "cb51bc42ae9dfb7345bfa7362a313baf",
"filesize": 374784,
"download_url": "https://github.com/GNS3/gns3-registry/tree/master/cloud-init/oracle-cloud",
"direct_download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/oracle-cloud/oracle-cloud-init-data.iso"
}
],
"versions": [
{
"name": "9.1",
"images": {
"hda_disk_image": "OL9U1_x86_64-kvm-b158.qcow",
"cdrom_image": "oracle-cloud-init-data.iso"
}
},
{
"name": "8.7",
"images": {
"hda_disk_image": "OL8U7_x86_64-kvm-b148.qcow",
"cdrom_image": "oracle-cloud-init-data.iso"
}
}
]
}

View File

@ -39,7 +39,8 @@
"version": "1.0",
"md5sum": "33ffda3a81436e305f37fb913edd6d43",
"filesize": 374784,
"download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/rocky-cloud/rocky-cloud-init-data.iso"
"download_url": "https://github.com/GNS3/gns3-registry/tree/master/cloud-init/rocky-cloud",
"direct_download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/rocky-cloud/rocky-cloud-init-data.iso"
}
],
"versions": [

View File

@ -29,51 +29,34 @@
{
"filename": "ubuntu-22.04-server-cloudimg-amd64.img",
"version": "22.04 (LTS)",
"md5sum": "ac2351289daa173fa1ed6b2b81d81d7c",
"filesize": 624295936,
"download_url": "https://cloud-images.ubuntu.com/releases/jammy/release/ubuntu-22.04-server-cloudimg-amd64.img"
"md5sum": "3ce0b84f9592482fb645e8253b979827",
"filesize": 686096384,
"download_url": "https://cloud-images.ubuntu.com/releases/jammy/release",
"direct_download_url": "https://cloud-images.ubuntu.com/releases/jammy/release/ubuntu-22.04-server-cloudimg-amd64.img"
},
{
"filename": "ubuntu-20.04-server-cloudimg-amd64.img",
"version": "20.04 (LTS)",
"md5sum": "044bc979b2238192ee3edb44e2bb6405",
"filesize": 552337408,
"download_url": "https://cloud-images.ubuntu.com/releases/focal/release-20210119.1/ubuntu-20.04-server-cloudimg-amd64.img"
"download_url": "https://cloud-images.ubuntu.com/releases/focal/release-20210119.1/",
"direct_download_url": "https://cloud-images.ubuntu.com/releases/focal/release-20210119.1/ubuntu-20.04-server-cloudimg-amd64.img"
},
{
"filename": "ubuntu-18.04-server-cloudimg-amd64.img",
"version": "18.04 (LTS)",
"md5sum": "f4134e7fa16d7fa766c7467cbe25c949",
"filesize": 336134144,
"download_url": "https://cloud-images.ubuntu.com/releases/18.04/release-20180426.2/ubuntu-18.04-server-cloudimg-amd64.img"
},
{
"filename": "ubuntu-17.10-server-cloudimg-amd64.img",
"version": "17.10",
"md5sum": "331b44f2b05858c251b3ea92c8b65152",
"filesize": 320405504,
"download_url": "https://cloud-images.ubuntu.com/releases/17.10/release-20180404/ubuntu-17.10-server-cloudimg-amd64.img"
},
{
"filename": "ubuntu-16.04-server-cloudimg-amd64-disk1.img",
"version": "16.04 (LTS)",
"md5sum": "22c124ba65ea096cdef8b0a197dd613a",
"filesize": 290193408,
"download_url": "https://cloud-images.ubuntu.com/releases/16.04/release-20180405/ubuntu-16.04-server-cloudimg-amd64-disk1.img"
},
{
"filename": "ubuntu-14.04-server-cloudimg-amd64-disk1.img",
"version": "14.04 (LTS)",
"md5sum": "d11b89321d41d0eeddcacf73bf0d2262",
"filesize": 262668800,
"download_url": "https://cloud-images.ubuntu.com/releases/14.04/release-20180404/ubuntu-14.04-server-cloudimg-amd64-disk1.img"
"download_url": "https://cloud-images.ubuntu.com/releases/18.04/release-20180426.2/",
"direct_download_url": "https://cloud-images.ubuntu.com/releases/18.04/release-20180426.2/ubuntu-18.04-server-cloudimg-amd64.img"
},
{
"filename": "ubuntu-cloud-init-data.iso",
"version": "1.0",
"md5sum": "328469100156ae8dbf262daa319c27ff",
"filesize": 131072,
"download_url": "https://github.com/asenci/gns3-ubuntu-cloud-init-data/raw/master/ubuntu-cloud-init-data.iso"
"version": "1.1",
"md5sum": "9a90ee8f88736204c756015b3cd86500",
"filesize": 374784,
"download_url": "https://github.com/GNS3/gns3-registry/tree/master/cloud-init/ubuntu-cloud",
"direct_download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/ubuntu-cloud/ubuntu-cloud-init-data.iso"
}
],
"versions": [
@ -97,27 +80,6 @@
"hda_disk_image": "ubuntu-18.04-server-cloudimg-amd64.img",
"cdrom_image": "ubuntu-cloud-init-data.iso"
}
},
{
"name": "17.10",
"images": {
"hda_disk_image": "ubuntu-17.10-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"
}
}
]
}

View File

@ -409,7 +409,10 @@ class BaseNode:
if self._wrapper_telnet_server:
self._wrap_console_writer.close()
if sys.version_info >= (3, 7, 0):
await self._wrap_console_writer.wait_closed()
try:
await self._wrap_console_writer.wait_closed()
except ConnectionResetError:
pass
self._wrapper_telnet_server.close()
await self._wrapper_telnet_server.wait_closed()
self._wrapper_telnet_server = None

View File

@ -150,9 +150,9 @@ class Docker(BaseManager):
data=data,
headers={"content-type": "application/json", },
timeout=timeout)
except (aiohttp.ClientResponseError, aiohttp.ClientOSError) as e:
except aiohttp.ClientError as e:
raise DockerError("Docker has returned an error: {}".format(str(e)))
except (asyncio.TimeoutError):
except asyncio.TimeoutError:
raise DockerError("Docker timeout " + method + " " + path)
if response.status >= 300:
body = await response.read()

View File

@ -85,7 +85,6 @@ class DockerVM(BaseNode):
self._ethernet_adapters = []
self._temporary_directory = None
self._telnet_servers = []
self._xvfb_process = None
self._vnc_process = None
self._vncconfig_process = None
self._console_resolution = console_resolution
@ -585,8 +584,8 @@ class DockerVM(BaseNode):
self._display = self._get_free_display_port()
tigervnc_path = shutil.which("Xtigervnc") or shutil.which("Xvnc")
if not (tigervnc_path or shutil.which("Xvfb") and shutil.which("x11vnc")):
raise DockerError("Please install TigerVNC (recommended) or Xvfb + x11vnc before using VNC support")
if not tigervnc_path:
raise DockerError("Please install TigerVNC server before using VNC support")
if tigervnc_path:
with open(os.path.join(self.working_dir, "vnc.log"), "w") as fd:
@ -600,29 +599,6 @@ class DockerVM(BaseNode):
"-SecurityTypes", "None",
":{}".format(self._display),
stdout=fd, stderr=subprocess.STDOUT)
else:
if restart is False:
self._xvfb_process = await asyncio.create_subprocess_exec("Xvfb",
"-nolisten", "tcp",
"-extension", "MIT-SHM",
":{}".format(self._display),
"-screen", "0",
self._console_resolution + "x16")
# We pass a port for TCPV6 due to a crash in X11VNC if not here: https://github.com/GNS3/gns3-server/issues/569
with open(os.path.join(self.working_dir, "vnc.log"), "w") as fd:
self._vnc_process = await asyncio.create_subprocess_exec("x11vnc",
"-forever",
"-nopw",
"-shared",
"-noshm",
"-geometry", self._console_resolution,
"-display", "WAIT:{}".format(self._display),
"-rfbport", str(self.console),
"-rfbportv6", str(self.console),
"-noncache",
"-listen", self._manager.port_manager.console_host,
stdout=fd, stderr=subprocess.STDOUT)
async def _start_vnc(self):
"""
@ -631,8 +607,8 @@ class DockerVM(BaseNode):
self._display = self._get_free_display_port()
tigervnc_path = shutil.which("Xtigervnc") or shutil.which("Xvnc")
if not (tigervnc_path or shutil.which("Xvfb") and shutil.which("x11vnc")):
raise DockerError("Please install TigerVNC server (recommended) or Xvfb + x11vnc before using VNC support")
if not tigervnc_path:
raise DockerError("Please install TigerVNC server before using VNC support")
await self._start_vnc_process()
x11_socket = os.path.join("/tmp/.X11-unix/", "X{}".format(self._display))
try:
@ -875,12 +851,6 @@ class DockerVM(BaseNode):
await self._vnc_process.wait()
except ProcessLookupError:
pass
if self._xvfb_process:
try:
self._xvfb_process.terminate()
await self._xvfb_process.wait()
except ProcessLookupError:
pass
if self._display:
display = "/tmp/.X11-unix/X{}".format(self._display)

View File

@ -2150,6 +2150,8 @@ class QemuVM(BaseNode):
else:
# newer QEMU networking syntax
device_string = "{},mac={}".format(adapter_type, mac)
if adapter_type == "virtio-net-pci":
device_string = "{},speed=10000,duplex=full".format(device_string)
bridge_id = math.floor(pci_device_id / 32)
if bridge_id > 0:
if pci_bridges_created < bridge_id:

View File

@ -450,7 +450,7 @@ class Compute:
elif response.type == aiohttp.WSMsgType.CLOSED:
pass
break
except aiohttp.client_exceptions.ClientResponseError as e:
except aiohttp.ClientError as e:
log.error("Client response error received on compute '{}' WebSocket '{}': {}".format(self._id, ws_url,e))
finally:
self._connected = False

View File

@ -122,9 +122,9 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
continue
return interface
async def _look_for_vboxnet(self, interface_number):
async def _look_for_vboxnet(self, backend_type, interface_number):
"""
Look for the VirtualBox network name associated with a host only interface.
Look for the VirtualBox network name associated with an interface.
:returns: None or vboxnet name
"""
@ -133,7 +133,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
for info in result.splitlines():
if '=' in info:
name, value = info.split('=', 1)
if name == "hostonlyadapter{}".format(interface_number):
if name == "{}{}".format(backend_type, interface_number):
return value.strip('"')
return None
@ -159,7 +159,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
return True
return False
async def _check_vboxnet_exists(self, vboxnet):
async def _check_vboxnet_exists(self, vboxnet, vboxnet_type):
"""
Check if the vboxnet interface exists
@ -167,7 +167,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
:returns: boolean
"""
properties = await self._execute("list", ["hostonlyifs"])
properties = await self._execute("list", ["{}".format(vboxnet_type)])
for prop in properties.splitlines():
try:
name, value = prop.split(':', 1)
@ -230,29 +230,42 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
if nat_interface_number < 0:
raise GNS3VMError('VM "{}" must have a NAT interface configured in order to start'.format(self.vmname))
hostonly_interface_number = await self._look_for_interface("hostonly")
if hostonly_interface_number < 0:
raise GNS3VMError('VM "{}" must have a host-only interface configured in order to start'.format(self.vmname))
if sys.platform.startswith("darwin") and parse_version(self._system_properties["API version"]) >= parse_version("7_0"):
# VirtualBox 7.0+ on macOS requires a host-only network interface
backend_type = "hostonly-network"
backend_description = "host-only network"
vboxnet_type = "hostonlynets"
interface_number = await self._look_for_interface("hostonlynetwork")
if interface_number < 0:
raise GNS3VMError('VM "{}" must have a network adapter attached to a host-only network in order to start'.format(self.vmname))
else:
backend_type = "hostonlyadapter"
backend_description = "host-only adapter"
vboxnet_type = "hostonlyifs"
interface_number = await self._look_for_interface("hostonly")
vboxnet = await self._look_for_vboxnet(hostonly_interface_number)
if interface_number < 0:
raise GNS3VMError('VM "{}" must have a network adapter attached to a {} in order to start'.format(self.vmname, backend_description))
vboxnet = await self._look_for_vboxnet(backend_type, interface_number)
if vboxnet is None:
raise GNS3VMError('A VirtualBox host-only network could not be found on network adapter {} for "{}"'.format(hostonly_interface_number, self._vmname))
raise GNS3VMError('A VirtualBox host-only network could not be found on network adapter {} for "{}"'.format(interface_number, self._vmname))
if not (await self._check_vboxnet_exists(vboxnet)):
if not (await self._check_vboxnet_exists(vboxnet, vboxnet_type)):
if sys.platform.startswith("win") and vboxnet == "vboxnet0":
# The GNS3 VM is configured with vboxnet0 by default which is not available
# on Windows. Try to patch this with the first available vboxnet we find.
first_available_vboxnet = await self._find_first_available_vboxnet()
if first_available_vboxnet is None:
raise GNS3VMError('Please add a VirtualBox host-only network with DHCP enabled and attached it to network adapter {} for "{}"'.format(hostonly_interface_number, self._vmname))
await self.set_hostonly_network(hostonly_interface_number, first_available_vboxnet)
raise GNS3VMError('Please add a VirtualBox host-only network with DHCP enabled and attached it to network adapter {} for "{}"'.format(interface_number, self._vmname))
await self.set_hostonly_network(interface_number, first_available_vboxnet)
vboxnet = first_available_vboxnet
else:
raise GNS3VMError('VirtualBox host-only network "{}" does not exist, please make the sure the network adapter {} configuration is valid for "{}"'.format(vboxnet,
hostonly_interface_number,
interface_number,
self._vmname))
if not (await self._check_dhcp_server(vboxnet)):
if backend_type == "hostonlyadapter" and not (await self._check_dhcp_server(vboxnet)):
raise GNS3VMError('DHCP must be enabled on VirtualBox host-only network "{}"'.format(vboxnet))
vm_state = await self._get_state()
@ -296,7 +309,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
await self._execute("controlvm", [self._vmname, "natpf{}".format(nat_interface_number),
"GNS3VM,tcp,{},{},,{}".format(ip_address, api_port, self.port)])
self.ip_address = await self._get_ip(hostonly_interface_number, api_port)
self.ip_address = await self._get_ip(interface_number, api_port)
log.info("GNS3 VM has been started with IP {}".format(self.ip_address))
self.running = True

View File

@ -15,6 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import ipaddress
import aiohttp
import asyncio
import html
@ -716,6 +717,17 @@ class Node:
"first_port_name": self._first_port_name,
"custom_adapters": self._custom_adapters
}
# add brackets around console host for http/https console type
console_host = str(self._compute.console_host)
if self._console_type == "http" or self._console_type == "https":
try:
ip = ipaddress.ip_address(console_host)
if isinstance(ip, ipaddress.IPv6Address):
console_host = '[' + console_host + ']'
except ValueError:
pass
return {
"compute_id": str(self._compute.id),
"project_id": self._project.id,
@ -725,7 +737,7 @@ class Node:
"node_directory": self._node_directory,
"name": self._name,
"console": self._console,
"console_host": str(self._compute.console_host),
"console_host": console_host,
"console_type": self._console_type,
"console_auto_start": self._console_auto_start,
"command_line": self._command_line,

View File

@ -798,7 +798,7 @@ class Project:
try:
await compute.post("/projects/{}/close".format(self._id), dont_connect=True)
# We don't care if a compute is down at this step
except (ComputeError, aiohttp.web.HTTPError, aiohttp.ClientResponseError, TimeoutError):
except (ComputeError, aiohttp.web.HTTPError, aiohttp.ClientError, TimeoutError):
pass
self._clean_pictures()
self._status = "closed"

View File

@ -58,7 +58,7 @@ class CrashReport:
Report crash to a third party service
"""
DSN = "https://75db396c4c294ad7a05ff7e8804ae5b8@o19455.ingest.sentry.io/38482"
DSN = "https://b929a9b102684c4d809647f1e613853a@o19455.ingest.sentry.io/38482"
_instance = None
def __init__(self):

File diff suppressed because one or more lines are too long

View File

@ -46,6 +46,6 @@
gtag('config', 'G-5D6FZL9923');
</script>
<script src="runtime.91a209cf21f6fb848205.js" defer></script><script src="polyfills-es5.865074f5cd9a121111a2.js" nomodule defer></script><script src="polyfills.2f91a039d848e57ff02e.js" defer></script><script src="main.96be36058f5df0ca7e7f.js" defer></script>
<script src="runtime.baa1121a4737aeb68bb7.js" defer></script><script src="polyfills-es5.865074f5cd9a121111a2.js" nomodule defer></script><script src="polyfills.2f91a039d848e57ff02e.js" defer></script><script src="main.8448c96e4facbe79a613.js" defer></script>
</body></html>

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
!function(){"use strict";var e,v={},g={};function n(e){var u=g[e];if(void 0!==u)return u.exports;var t=g[e]={id:e,loaded:!1,exports:{}};return v[e](t,t.exports,n),t.loaded=!0,t.exports}n.m=v,e=[],n.O=function(u,t,a,o){if(!t){var r=1/0;for(i=0;i<e.length;i++){t=e[i][0],a=e[i][1],o=e[i][2];for(var l=!0,f=0;f<t.length;f++)(!1&o||r>=o)&&Object.keys(n.O).every(function(b){return n.O[b](t[f])})?t.splice(f--,1):(l=!1,o<r&&(r=o));if(l){e.splice(i--,1);var s=a();void 0!==s&&(u=s)}}return u}o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,a,o]},n.n=function(e){var u=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(u,{a:u}),u},n.d=function(e,u){for(var t in u)n.o(u,t)&&!n.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:u[t]})},n.f={},n.e=function(e){return Promise.all(Object.keys(n.f).reduce(function(u,t){return n.f[t](e,u),u},[]))},n.u=function(e){return e+".52bf50eec59e1bcb0895.js"},n.miniCssF=function(e){return"styles.f8555f2eecf8cf87f666.css"},n.hmd=function(e){return(e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:function(){throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e},n.o=function(e,u){return Object.prototype.hasOwnProperty.call(e,u)},function(){var e={},u="gns3-web-ui:";n.l=function(t,a,o,i){if(e[t])e[t].push(a);else{var r,l;if(void 0!==o)for(var f=document.getElementsByTagName("script"),s=0;s<f.length;s++){var c=f[s];if(c.getAttribute("src")==t||c.getAttribute("data-webpack")==u+o){r=c;break}}r||(l=!0,(r=document.createElement("script")).charset="utf-8",r.timeout=120,n.nc&&r.setAttribute("nonce",n.nc),r.setAttribute("data-webpack",u+o),r.src=n.tu(t)),e[t]=[a];var d=function(h,b){r.onerror=r.onload=null,clearTimeout(p);var _=e[t];if(delete e[t],r.parentNode&&r.parentNode.removeChild(r),_&&_.forEach(function(m){return m(b)}),h)return h(b)},p=setTimeout(d.bind(null,void 0,{type:"timeout",target:r}),12e4);r.onerror=d.bind(null,r.onerror),r.onload=d.bind(null,r.onload),l&&document.head.appendChild(r)}}}(),n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},function(){var e;n.tu=function(u){return void 0===e&&(e={createScriptURL:function(t){return t}},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(u)}}(),n.p="",function(){var e={666:0};n.f.j=function(a,o){var i=n.o(e,a)?e[a]:void 0;if(0!==i)if(i)o.push(i[2]);else if(666!=a){var r=new Promise(function(c,d){i=e[a]=[c,d]});o.push(i[2]=r);var l=n.p+n.u(a),f=new Error;n.l(l,function(c){if(n.o(e,a)&&(0!==(i=e[a])&&(e[a]=void 0),i)){var d=c&&("load"===c.type?"missing":c.type),p=c&&c.target&&c.target.src;f.message="Loading chunk "+a+" failed.\n("+d+": "+p+")",f.name="ChunkLoadError",f.type=d,f.request=p,i[1](f)}},"chunk-"+a,a)}else e[a]=0},n.O.j=function(a){return 0===e[a]};var u=function(a,o){var f,s,i=o[0],r=o[1],l=o[2],c=0;for(f in r)n.o(r,f)&&(n.m[f]=r[f]);if(l)var d=l(n);for(a&&a(o);c<i.length;c++)n.o(e,s=i[c])&&e[s]&&e[s][0](),e[i[c]]=0;return n.O(d)},t=self.webpackChunkgns3_web_ui=self.webpackChunkgns3_web_ui||[];t.forEach(u.bind(null,0)),t.push=u.bind(null,t.push.bind(t))}()}();

View File

@ -71,10 +71,10 @@ async def subprocess_check_output(*args, cwd=None, env=None, stderr=False):
if stderr:
proc = await asyncio.create_subprocess_exec(*args, stderr=asyncio.subprocess.PIPE, cwd=cwd, env=env)
output = await proc.stderr.read()
_, output = await proc.communicate()
else:
proc = await asyncio.create_subprocess_exec(*args, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL, cwd=cwd, env=env)
output = await proc.stdout.read()
output, _ = await proc.communicate()
if output is None:
return ""
# If we received garbage we ignore invalid characters

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.39"
__version_info__ = (2, 2, 39, 0)
__version__ = "2.2.40"
__version_info__ = (2, 2, 40, 0)
if "dev" in __version__:
try:

View File

@ -1115,8 +1115,7 @@ async def test_close(vm, port_manager):
async def test_close_vnc(vm):
vm._console_type = "vnc"
vm._x11vnc_process = MagicMock()
vm._xvfb_process = MagicMock()
vm._vnc_process = MagicMock()
with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="stopped"):
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query:
@ -1124,7 +1123,7 @@ async def test_close_vnc(vm):
mock_query.assert_called_with("DELETE", "containers/e90e34656842", params={"force": 1, "v": 1})
assert vm._closed is True
assert vm._xvfb_process.terminate.called
assert vm._vnc_process.terminate.called
async def test_get_namespace(vm):

View File

@ -102,6 +102,7 @@ async def test_start(vm):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=mock_process) as mock_exec:
mock_process.returncode = None
mock_process.communicate = AsyncioMagicMock(return_value=(None, None))
await vm.start()
assert vm.is_running()
assert vm.command_line == ' '.join(mock_exec.call_args[0])
@ -130,6 +131,7 @@ async def test_start_with_iourc(vm, tmpdir):
with patch("gns3server.config.Config.get_section_config", return_value={"iourc_path": fake_file}):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=mock_process) as exec_mock:
mock_process.returncode = None
mock_process.communicate = AsyncioMagicMock(return_value=(None, None))
await vm.start()
assert vm.is_running()
arsgs, kwargs = exec_mock.call_args
@ -165,11 +167,12 @@ async def test_stop(vm):
future = asyncio.Future()
future.set_result(True)
process.wait.return_value = future
process.returncode = None
process.communicate = AsyncioMagicMock(return_value=(None, None))
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"):
await vm.start()
process.returncode = None
assert vm.is_running()
await vm.stop()
assert vm.is_running() is False
@ -190,6 +193,7 @@ async def test_reload(vm, fake_iou_bin):
future.set_result(True)
process.wait.return_value = future
process.returncode = None
process.communicate = AsyncioMagicMock(return_value=(None, None))
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"):
@ -202,10 +206,13 @@ async def test_reload(vm, fake_iou_bin):
async def test_close(vm, port_manager):
process = MagicMock()
process.returncode = None
process.communicate = AsyncioMagicMock(return_value=(None, None))
vm._start_ubridge = AsyncioMagicMock(return_value=True)
vm._ubridge_send = AsyncioMagicMock()
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
await vm.start()
port = vm.console
await vm.close()

View File

@ -737,6 +737,20 @@ async def test_build_command_large_number_of_adapters(vm):
await vm._build_command()
async def test_build_command_with_virtio_net_pci_adapter(vm):
"""
Test virtio-net-pci adapter which has parameters speed=1000 & duplex=full hard-coded
"""
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.4.0")
vm.adapters = 1
vm.mac_address = "00:00:ab:0e:0f:09"
vm._adapter_type = "virtio-net-pci"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
cmd = await vm._build_command()
assert "virtio-net-pci,mac=00:00:ab:0e:0f:09,speed=10000,duplex=full,netdev=gns3-0" in cmd
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
async def test_build_command_with_invalid_options(vm):