Merge pull request #2192 from GNS3/2.2

Release v2.2.38
pull/2211/head
Jeremy Grossmann 1 year ago committed by GitHub
commit 0406083991
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,5 +1,14 @@
# Change Log # Change Log
## 2.2.38 28/02/2023
* Bundle web-ui v2.2.38
* Fix c7200_i0_log.txt is created in the current directory. Fixes #2191
* Check swtpm version and start swtpm before qemu
* Fix broken websocket console with Python 3.11
* Fix "cannot reopen console". Ref #2182
* Fix Qemu binary not set when adding appliance from template
## 2.2.37 25/01/2023 ## 2.2.37 25/01/2023
* Fix link communication issues on Windows with uBridge * Fix link communication issues on Windows with uBridge

@ -33,6 +33,27 @@
"filesize": 1592000512, "filesize": 1592000512,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/10.1(1)" "download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/10.1(1)"
}, },
{
"filename": "nexus9300v.10.1.1.qcow2",
"version": "9300v 10.1.1",
"md5sum": "4051bdb96aff6e54b72b7e3b06c9d6eb",
"filesize": 1990983680,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/10.1(1)"
},
{
"filename": "nexus9500v.9.3.9.qcow2",
"version": "9500v 9.3.9",
"md5sum": "30c25039927f89aebe73ea20d15abd6d",
"filesize": 1980760064,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/9.3(9)"
},
{
"filename": "nexus9300v.9.3.9.qcow2",
"version": "9300v 9.3.9",
"md5sum": "e807005cb7d2d2957b4af0e59f368b36",
"filesize": 1980563456,
"download_url": "https://software.cisco.com/download/home/286312239/type/282088129/release/9.3(9)"
},
{ {
"filename": "nexus9300v.9.3.8.qcow2", "filename": "nexus9300v.9.3.8.qcow2",
"version": "9300v 9.3.8", "version": "9300v 9.3.8",
@ -184,6 +205,27 @@
"hda_disk_image": "nexus9500v64.10.1.1.qcow2" "hda_disk_image": "nexus9500v64.10.1.1.qcow2"
} }
}, },
{
"name": "9300v 10.1.1",
"images": {
"bios_image": "OVMF-20160813.fd",
"hda_disk_image": "nexus9300v.10.1.1.qcow2"
}
},
{
"name": "9500v 9.3.9",
"images": {
"bios_image": "OVMF-20160813.fd",
"hda_disk_image": "nexus9500v.9.3.9.qcow2"
}
},
{
"name": "9300v 9.3.9",
"images": {
"bios_image": "OVMF-20160813.fd",
"hda_disk_image": "nexus9300v.9.3.9.qcow2"
}
},
{ {
"name": "9300v 9.3.8", "name": "9300v 9.3.8",
"images": { "images": {

@ -27,6 +27,13 @@
"kvm": "allow" "kvm": "allow"
}, },
"images": [ "images": [
{
"filename": "FWB_KVM-v700-build0129-FORTINET.out.kvm.qcow2",
"version": "7.0.5",
"md5sum": "dc14114c68cf42df322e5b89bffd9bf7",
"filesize": 258146816,
"download_url": "https://support.fortinet.com/Download/FirmwareImages.aspx"
},
{ {
"filename": "FWB_KVM-v700-build0097-FORTINET.out.kvm.qcow2", "filename": "FWB_KVM-v700-build0097-FORTINET.out.kvm.qcow2",
"version": "7.0.1", "version": "7.0.1",
@ -128,6 +135,13 @@
} }
], ],
"versions": [ "versions": [
{
"name": "7.0.5",
"images": {
"hda_disk_image": "FWB_KVM-v700-build0129-FORTINET.out.kvm.qcow2",
"hdb_disk_image": "empty30G.qcow2"
}
},
{ {
"name": "7.0.1", "name": "7.0.1",
"images": { "images": {

@ -27,6 +27,13 @@
"options": "-smp 2" "options": "-smp 2"
}, },
"images": [ "images": [
{
"filename": "PA-VM-KVM-10.1.0.qcow2",
"version": "10.1.0",
"md5sum": "8266fd412a22694749f2cd4afcd5fa33",
"filesize": 3597467648,
"download_url": "https://support.paloaltonetworks.com/Updates/SoftwareUpdates/"
},
{ {
"filename": "PA-VM-KVM-10.0.0.qcow2", "filename": "PA-VM-KVM-10.0.0.qcow2",
"version": "10.0.0", "version": "10.0.0",
@ -120,6 +127,12 @@
} }
], ],
"versions": [ "versions": [
{
"name": "10.1.0",
"images": {
"hda_disk_image": "PA-VM-KVM-10.1.0.qcow2"
}
},
{ {
"name": "10.0.0", "name": "10.0.0",
"images": { "images": {

@ -17,7 +17,7 @@
"qemu": { "qemu": {
"adapter_type": "e1000", "adapter_type": "e1000",
"adapters": 1, "adapters": 1,
"ram": 96, "ram": 128,
"hda_disk_interface": "virtio", "hda_disk_interface": "virtio",
"arch": "i386", "arch": "i386",
"console_type": "vnc", "console_type": "vnc",
@ -28,7 +28,7 @@
{ {
"filename": "linux-tinycore-11.1.qcow2", "filename": "linux-tinycore-11.1.qcow2",
"version": "11.1", "version": "11.1",
"md5sum": "993d1ce9b86cb131c90e8263891d51b8", "md5sum": "00a65300a1dcc956e4e677c638bf4445",
"filesize": 33816576, "filesize": 33816576,
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/", "download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "http://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/linux-tinycore-11.1.qcow2" "direct_download_url": "http://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/linux-tinycore-11.1.qcow2"

@ -1,45 +0,0 @@
{
"appliance_id": "d2a23e69-9e92-4c3f-83c8-8caa1aa58ece",
"name": "Ubuntu Server",
"category": "guest",
"description": "This is a custom Ubuntu server which comes with Canonical security updates, Xorg and Telnetd",
"vendor_name": "Canonical Inc.",
"vendor_url": "https://www.ubuntu.com",
"documentation_url": "https://help.ubuntu.com",
"product_name": "Ubuntu",
"product_url": "https://ubuntu.com/server",
"registry_version": 4,
"status": "stable",
"maintainer": "Mohamad Siblini",
"maintainer_email": "info@ictkin.com",
"usage": "Username: gns3\nPassword: gns3 | MD5: 435f15a54f7f673e302ad26f05226e0e",
"port_name_format": "ens{0}",
"qemu": {
"adapter_type": "virtio-net-pci",
"adapters": 1,
"ram": 2048,
"hda_disk_interface": "virtio",
"arch": "x86_64",
"console_type": "vnc",
"boot_priority": "c",
"kvm": "require",
"options": "-vga virtio"
},
"images": [
{
"filename": "Ubuntu Server 18.04.3 LTS (64bit).vmdk",
"version": "18.04.3 LTS Server",
"md5sum": "435f15a54f7f673e302ad26f05226e0e",
"filesize": 2707814912,
"download_url": "https://www.ictkin.com/gns3-appliance/"
}
],
"versions": [
{
"name": "18.04.3 LTS Server",
"images": {
"hda_disk_image": "Ubuntu Server 18.04.3 LTS (64bit).vmdk"
}
}
]
}

@ -469,7 +469,18 @@ class BaseNode:
try: try:
# keep forwarding websocket data in both direction # keep forwarding websocket data in both direction
await asyncio.wait([ws_forward(telnet_writer), telnet_forward(telnet_reader)], return_when=asyncio.FIRST_COMPLETED) if sys.version_info >= (3, 11, 0):
# Starting with Python 3.11, passing coroutine objects to wait() directly is forbidden.
aws = [asyncio.create_task(ws_forward(telnet_writer)), asyncio.create_task(telnet_forward(telnet_reader))]
else:
aws = [ws_forward(telnet_writer), telnet_forward(telnet_reader)]
done, pending = await asyncio.wait(aws, return_when=asyncio.FIRST_COMPLETED)
for task in done:
if task.exception():
log.warning(f"Exception while forwarding WebSocket data to Telnet server {task.exception()}")
for task in pending:
task.cancel()
finally: finally:
log.info("Client has disconnected from console WebSocket") log.info("Client has disconnected from console WebSocket")
if not ws.closed: if not ws.closed:

@ -273,7 +273,7 @@ class Dynamips(BaseManager):
""" """
try: try:
output = await subprocess_check_output(dynamips_path) output = await subprocess_check_output(dynamips_path, "-P", "none")
match = re.search(r"Cisco Router Simulation Platform \(version\s+([\d.]+)", output) match = re.search(r"Cisco Router Simulation Platform \(version\s+([\d.]+)", output)
if match: if match:
version = match.group(1) version = match.group(1)

@ -223,7 +223,7 @@ class Qemu(BaseManager):
version = match.group(1) version = match.group(1)
return version return version
else: else:
raise QemuError("Could not determine the Qemu version for {}".format(qemu_path)) raise QemuError("Could not determine the Qemu version for '{}'".format(qemu_path))
except (OSError, subprocess.SubprocessError) as e: except (OSError, subprocess.SubprocessError) as e:
raise QemuError("Error while looking for the Qemu version: {}".format(e)) raise QemuError("Error while looking for the Qemu version: {}".format(e))
@ -242,10 +242,29 @@ class Qemu(BaseManager):
version = match.group(1) version = match.group(1)
return version return version
else: else:
raise QemuError("Could not determine the Qemu-img version for {}".format(qemu_img_path)) raise QemuError("Could not determine the Qemu-img version for '{}'".format(qemu_img_path))
except (OSError, subprocess.SubprocessError) as e: except (OSError, subprocess.SubprocessError) as e:
raise QemuError("Error while looking for the Qemu-img version: {}".format(e)) raise QemuError("Error while looking for the Qemu-img version: {}".format(e))
@staticmethod
async def get_swtpm_version(swtpm_path):
"""
Gets the swtpm version.
:param swtpm_path: path to swtpm executable.
"""
try:
output = await subprocess_check_output(swtpm_path, "--version")
match = re.search(r"version\s+([\d.]+)", output)
if match:
version = match.group(1)
return version
else:
raise QemuError("Could not determine the swtpm version for '{}'".format(swtpm_path))
except (OSError, subprocess.SubprocessError) as e:
raise QemuError("Error while looking for the swtpm version: {}".format(e))
@staticmethod @staticmethod
def get_haxm_windows_version(): def get_haxm_windows_version():
""" """

@ -216,7 +216,7 @@ class QemuVM(BaseNode):
if qemu_bin == "qemu": if qemu_bin == "qemu":
self._platform = "i386" self._platform = "i386"
else: else:
self._platform = re.sub(r'^qemu-system-(.*)$', r'\1', qemu_bin, re.IGNORECASE) self._platform = re.sub(r'^qemu-system-(\w+).*$', r'\1', qemu_bin, re.IGNORECASE)
if self._platform.split(".")[0] not in QEMU_PLATFORMS: if self._platform.split(".")[0] not in QEMU_PLATFORMS:
raise QemuError("Platform {} is unknown".format(self._platform)) raise QemuError("Platform {} is unknown".format(self._platform))
log.info('QEMU VM "{name}" [{id}] has set the QEMU path to {qemu_path}'.format(name=self._name, log.info('QEMU VM "{name}" [{id}] has set the QEMU path to {qemu_path}'.format(name=self._name,
@ -1079,6 +1079,10 @@ class QemuVM(BaseNode):
# check if there is enough RAM to run # check if there is enough RAM to run
self.check_available_ram(self.ram) self.check_available_ram(self.ram)
# start swtpm (TPM emulator) first if TPM is enabled
if self._tpm:
await self._start_swtpm()
command = await self._build_command() command = await self._build_command()
command_string = " ".join(shlex_quote(s) for s in command) command_string = " ".join(shlex_quote(s) for s in command)
try: try:
@ -1104,8 +1108,6 @@ class QemuVM(BaseNode):
await self._set_process_priority() await self._set_process_priority()
if self._cpu_throttling: if self._cpu_throttling:
self._set_cpu_throttling() self._set_cpu_throttling()
if self._tpm:
self._start_swtpm()
if "-enable-kvm" in command_string or "-enable-hax" in command_string: if "-enable-kvm" in command_string or "-enable-hax" in command_string:
self._hw_virtualization = True self._hw_virtualization = True
@ -2019,10 +2021,9 @@ class QemuVM(BaseNode):
options.extend(["-kernel", self._kernel_image.replace(",", ",,")]) options.extend(["-kernel", self._kernel_image.replace(",", ",,")])
if self._kernel_command_line: if self._kernel_command_line:
options.extend(["-append", self._kernel_command_line]) options.extend(["-append", self._kernel_command_line])
return options return options
def _start_swtpm(self): async def _start_swtpm(self):
""" """
Start swtpm (TPM emulator) Start swtpm (TPM emulator)
""" """
@ -2035,6 +2036,10 @@ class QemuVM(BaseNode):
swtpm = shutil.which("swtpm") swtpm = shutil.which("swtpm")
if not swtpm: if not swtpm:
raise QemuError("Could not find swtpm (TPM emulator)") raise QemuError("Could not find swtpm (TPM emulator)")
swtpm_version = await self.manager.get_swtpm_version(swtpm)
if swtpm_version and parse_version(swtpm_version) < parse_version("0.8.0"):
# swtpm >= version 0.8.0 is required
raise QemuError("swtpm version 0.8.0 or above must be installed (detected version is {})".format(swtpm_version))
try: try:
command = [ command = [
swtpm, swtpm,
@ -2066,6 +2071,8 @@ class QemuVM(BaseNode):
""" """
tpm_sock = os.path.join(self.temporary_directory, "swtpm.sock") tpm_sock = os.path.join(self.temporary_directory, "swtpm.sock")
if not os.path.exists(tpm_sock):
raise QemuError("swtpm socket file '{}' does not exist".format(tpm_sock))
options = [ options = [
"-chardev", "-chardev",
"socket,id=chrtpm,path={}".format(tpm_sock), "socket,id=chrtpm,path={}".format(tpm_sock),

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

@ -29,6 +29,9 @@ from gns3server.schemas.node import (
NODE_DUPLICATE_SCHEMA NODE_DUPLICATE_SCHEMA
) )
import logging
log = logging.getLogger(__name__)
class NodeHandler: class NodeHandler:
""" """
@ -500,6 +503,8 @@ class NodeHandler:
await ws.send_bytes(msg.data) await ws.send_bytes(msg.data)
elif msg.type == aiohttp.WSMsgType.ERROR: elif msg.type == aiohttp.WSMsgType.ERROR:
break break
except ConnectionResetError:
log.info("Websocket console connection with compute disconnected")
finally: finally:
if not ws.closed: if not ws.closed:
await ws.close() await ws.close()

@ -35,7 +35,7 @@ QEMU_TEMPLATE_PROPERTIES = {
"platform": { "platform": {
"description": "Platform to emulate", "description": "Platform to emulate",
"enum": QEMU_PLATFORMS, "enum": QEMU_PLATFORMS,
"default": "i386" "default": ""
}, },
"linked_clone": { "linked_clone": {
"description": "Whether the VM is a linked clone or not", "description": "Whether the VM is a linked clone or not",

@ -46,6 +46,6 @@
gtag('config', 'G-5D6FZL9923'); gtag('config', 'G-5D6FZL9923');
</script> </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.b8506a62709d0cc9f214.js" defer></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.11410ae4eaf4d4c08cd0.js" defer></script>
</body></html> </body></html>

@ -203,8 +203,7 @@ class AsyncioTelnetServer:
except ConnectionError: except ConnectionError:
async with self._lock: async with self._lock:
network_writer.close() network_writer.close()
if sys.version_info >= (3, 7, 0): # await network_writer.wait_closed() # this doesn't work in Python 3.6
await network_writer.wait_closed()
if self._reader_process == network_reader: if self._reader_process == network_reader:
self._reader_process = None self._reader_process = None
# Cancel current read from this reader # Cancel current read from this reader
@ -220,8 +219,7 @@ class AsyncioTelnetServer:
writer.write_eof() writer.write_eof()
await writer.drain() await writer.drain()
writer.close() writer.close()
if sys.version_info >= (3, 7, 0): # await writer.wait_closed() # this doesn't work in Python 3.6
await writer.wait_closed()
except (AttributeError, ConnectionError): except (AttributeError, ConnectionError):
continue continue

@ -23,8 +23,8 @@
# or negative for a release candidate or beta (after the base version # or negative for a release candidate or beta (after the base version
# number has been incremented) # number has been incremented)
__version__ = "2.2.37" __version__ = "2.2.38"
__version_info__ = (2, 2, 37, 0) __version_info__ = (2, 2, 38, 0)
if "dev" in __version__: if "dev" in __version__:
try: try:

@ -409,7 +409,8 @@ async def test_tpm_option(vm, tmpdir, fake_qemu_img_binary):
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0") vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
vm._tpm = True vm._tpm = True
tpm_sock = os.path.join(vm.temporary_directory, "swtpm.sock") tpm_sock = os.path.join(vm.temporary_directory, "swtpm.sock")
options = await vm._build_command() with patch("os.path.exists", return_value=True) as os_path:
options = await vm._build_command()
assert '-chardev socket,id=chrtpm,path={}'.format(tpm_sock) in ' '.join(options) assert '-chardev socket,id=chrtpm,path={}'.format(tpm_sock) in ' '.join(options)
assert '-tpmdev emulator,id=tpm0,chardev=chrtpm' in ' '.join(options) assert '-tpmdev emulator,id=tpm0,chardev=chrtpm' in ' '.join(options)
assert '-device tpm-tis,tpmdev=tpm0' in ' '.join(options) assert '-device tpm-tis,tpmdev=tpm0' in ' '.join(options)

Loading…
Cancel
Save