Compare commits

...
23 Commits
Author SHA1 Message Date
grossmj bccdfc97d1 Release 2.1.12 2019-01-23 15:40:38 +08:00
Jeremy Grossmann 792c4310eb Merge pull request #1502 from GNS3/svg-symbols-fixes
Tune how to get the size of SVG images.
2019-01-22 00:41:26 +07:00
grossmj 3e21f96bf9 Fix indentation issue. Ref https://github.com/GNS3/gns3-gui/issues/2674
(cherry picked from commit c14d79a3d5)
2019-01-21 23:51:46 +07:00
grossmj 5f932fee9f Tune how to get the size of SVG images. Ref https://github.com/GNS3/gns3-gui/issues/2674.
* Default for missing height/width is "100%" as defined in the SVG specification
* Better error message, if viewBox attribute is missing
* Removal of "%" in percent more fault tolerant by using rstrip("%")

(cherry picked from commit e3757a8955)
2019-01-21 23:49:43 +07:00
grossmj ef38ccfefa Automatically create a symbolic link to the IOU image in the IOU working directory. Fixes #1484 2018-12-17 22:42:18 -06:00
grossmj 670b6d689a Merge remote-tracking branch 'origin/2.1' into 2.1 2018-12-14 19:53:51 -06:00
grossmj fc75a6b8d3 Fix link pause/filters only work for the first interface of Docker containers. Fixes #1482 2018-12-14 19:53:43 -06:00
Jeremy Grossmann 647ac87c89 Merge pull request #1476 from ddragic/x11vnc
Docker: fix x11vnc not starting
2018-11-29 07:03:58 +07:00
Dušan Dragić 817a053dfc docker_vm: fix x11vnc not starting 2018-11-29 00:37:20 +01:00
Jeremy Grossmann df4e4bec24 Merge pull request #1472 from GNS3/docker-console-resize
Telnet console resize support for Docker VM. Fixes #1471
2018-11-27 15:17:34 +07:00
grossmj 60ac6d2dfe Telnet console resize support for Docker VM. 2018-11-27 15:06:56 +07:00
grossmj c0a0a13bdd Avoid _fix_permissions() to be called twice when stopping Docker VM. Ref #1428 2018-11-26 15:53:24 +07:00
grossmj a3044ede77 Fix _fix_permissions() garbles permissions in Docker VM. Ref #1428 2018-11-25 17:11:42 +07:00
grossmj df3baffd9b Fix "None is not of type 'integer'" when opening project containing a Qemu VM. Fixes #2610. 2018-11-24 19:56:29 +07:00
grossmj e7b8309a80 Fix Docker VNC tests. Ref #1438 2018-11-11 23:25:23 +08:00
grossmj 029344da14 Only require Xtigervnc or Xvfb+x11vnc for Docker with vnc console. Ref #1438 2018-11-11 22:33:58 +08:00
grossmj d0bab9947e Support tigervnc in Docker VM. Ref #1438 2018-11-11 21:07:33 +08:00
grossmj e4a6db8ebc Fix some typos. 2018-10-04 15:22:42 +02:00
grossmj 181a31be32 Update minimum VIX version requirements for VMware. Ref #1415. 2018-10-02 11:22:32 +02:00
grossmj 8d368cd0f6 Development on 2.1.12dev1 2018-09-28 20:50:03 +02:00
grossmj 41d4ecc4b7 Release v2.1.11 2018-09-28 20:47:44 +02:00
grossmj 4d95e0b51f Catch some exceptions. 2018-09-28 15:04:38 +02:00
grossmj 4efdefaf5a Development on 2.1.11dev1 2018-09-15 11:23:18 +02:00
24 changed files with 183 additions and 93 deletions

No files matched your search

+17 -1
View File
@@ -1,5 +1,21 @@
# Change Log
## 2.1.12 23/01/2019
* Tune how to get the size of SVG images. Ref https://github.com/GNS3/gns3-gui/issues/2674.
* Automatically create a symbolic link to the IOU image in the IOU working directory. Fixes #1484
* Fix link pause/filters only work for the first interface of Docker containers. Fixes #1482
* Telnet console resize support for Docker VM.
* Fix _fix_permissions() garbles permissions in Docker VM. Ref #1428
* Fix "None is not of type 'integer'" when opening project containing a Qemu VM. Fixes #2610.
* Only require Xtigervnc or Xvfb+x11vnc for Docker with vnc console. Ref #1438
* Support tigervnc in Docker VM. Ref #1438
* Update minimum VIX version requirements for VMware. Ref #1415.
## 2.1.11 28/09/2018
* Catch some exceptions.
## 2.1.10 15/09/2018
* Include locale information and GNS3 VM version in crash reports.
@@ -677,7 +693,7 @@
* Fix naming of IOU serial interfaces
* Improve timeout management
* When exporting debug information export GNS3 VM vmx content
* /debug for exporting debug informations
* /debug for exporting debug information
* Raise error if using a non linked clone VM twice
* Fix a possible deadlock at exit
* Fix import of some old dynamips topologies
+1 -1
View File
@@ -5,7 +5,7 @@
GET /v2/compute/debug
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Return debug informations about the compute
Return debug information about the compute
Response status codes
**********************
+72 -36
View File
@@ -24,6 +24,7 @@ import shutil
import psutil
import shlex
import aiohttp
import subprocess
import os
from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer
@@ -82,12 +83,14 @@ class DockerVM(BaseNode):
self._ethernet_adapters = []
self._temporary_directory = None
self._telnet_servers = []
self._x11vnc_process = None
self._vnc_process = None
self._xvfb_process = None
self._console_resolution = console_resolution
self._console_http_path = console_http_path
self._console_http_port = console_http_port
self._console_websocket = None
self._extra_hosts = extra_hosts
self._permissions_fixed = False
self._volumes = []
# Keep a list of created bridge
@@ -439,12 +442,14 @@ class DockerVM(BaseNode):
if self.console_type == "telnet":
yield from self._start_console()
elif self.console_type == "http" or self.console_type == "https":
yield from self._start_http()
if self.allocate_aux:
yield from self._start_aux()
self._permissions_fixed = False
self.status = "started"
log.info("Docker container '{name}' [{image}] started listen for {console_type} on {console}".format(name=self._name,
image=self._image,
@@ -460,11 +465,10 @@ class DockerVM(BaseNode):
# We can not use the API because docker doesn't expose a websocket api for exec
# https://github.com/GNS3/gns3-gui/issues/1039
try:
process = yield from asyncio.subprocess.create_subprocess_exec(
"docker", "exec", "-i", self._cid, "/gns3/bin/busybox", "script", "-qfc", "while true; do TERM=vt100 /gns3/bin/busybox sh; done", "/dev/null",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,
stdin=asyncio.subprocess.PIPE)
process = yield from asyncio.subprocess.create_subprocess_exec("docker", "exec", "-i", self._cid, "/gns3/bin/busybox", "script", "-qfc", "while true; do TERM=vt100 /gns3/bin/busybox sh; done", "/dev/null",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,
stdin=asyncio.subprocess.PIPE)
except OSError as e:
raise DockerError("Could not start auxiliary console process: {}".format(e))
server = AsyncioTelnetServer(reader=process.stdout, writer=process.stdin, binary=True, echo=True)
@@ -472,7 +476,7 @@ class DockerVM(BaseNode):
self._telnet_servers.append((yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.aux)))
except OSError as e:
raise DockerError("Could not start Telnet server on socket {}:{}: {}".format(self._manager.port_manager.console_host, self.aux, e))
log.debug("Docker container '%s' started listen for auxilary telnet on %d", self.name, self.aux)
log.debug("Docker container '%s' started listen for auxiliary telnet on %d", self.name, self.aux)
@asyncio.coroutine
def _fix_permissions(self):
@@ -482,6 +486,7 @@ class DockerVM(BaseNode):
"""
state = yield from self._get_container_state()
log.info("Docker container '{name}' fix ownership, state = {state}".format(name=self._name, state=state))
if state == "stopped" or state == "exited":
# We need to restart it to fix permissions
yield from self.manager.query("POST", "containers/{}/start".format(self._cid))
@@ -509,6 +514,7 @@ class DockerVM(BaseNode):
except OSError as e:
raise DockerError("Could not fix permissions for {}: {}".format(volume, e))
yield from process.wait()
self._permissions_fixed = True
@asyncio.coroutine
def _start_vnc(self):
@@ -517,19 +523,46 @@ class DockerVM(BaseNode):
"""
self._display = self._get_free_display_port()
if shutil.which("Xvfb") is None or shutil.which("x11vnc") is None:
raise DockerError("Please install Xvfb and x11vnc before using VNC support")
self._xvfb_process = yield from asyncio.create_subprocess_exec("Xvfb", "-nolisten", "tcp", ":{}".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
self._x11vnc_process = yield from asyncio.create_subprocess_exec("x11vnc", "-forever", "-nopw", "-shared", "-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)
if not (shutil.which("Xtigervnc") or shutil.which("Xvfb") and shutil.which("x11vnc")):
raise DockerError("Please install tigervnc-standalone-server (recommended) or Xvfb + x11vnc before using VNC support")
if shutil.which("Xtigervnc"):
with open(os.path.join(self.working_dir, "vnc.log"), "w") as fd:
self._vnc_process = yield from asyncio.create_subprocess_exec("Xtigervnc",
"-geometry", self._console_resolution,
"-depth", "16",
"-interface", self._manager.port_manager.console_host,
"-rfbport", str(self.console),
"-AlwaysShared",
"-SecurityTypes", "None",
":{}".format(self._display),
stdout=fd, stderr=subprocess.STDOUT)
else:
self._xvfb_process = yield from asyncio.create_subprocess_exec("Xvfb",
"-nolisten",
"tcp", ":{}".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 = yield from asyncio.create_subprocess_exec("x11vnc",
"-forever",
"-nopw",
"-shared",
"-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)
x11_socket = os.path.join("/tmp/.X11-unix/", "X{}".format(self._display))
yield from wait_for_file_creation(x11_socket)
#monitor_process(self._vnc_process, self._vnc_callback)
#monitor_process(self._xvfb_process, self._xvfb_callback)
#monitor_process(self._x11vnc_process, self._x11vnc_callback)
def _xvfb_callback(self, returncode):
def _vnc_callback(self, returncode):
"""
Called when the process has stopped.
@@ -537,17 +570,7 @@ class DockerVM(BaseNode):
"""
if returncode != 0:
self.project.emit("log.error", {"message": "The Xvfb process has stopped, return code: {}.".format(returncode)})
def _x11vnc_callback(self, returncode):
"""
Called when the process has stopped.
:param returncode: Process returncode
"""
if returncode != 0:
self.project.emit("log.error", {"message": "The x11vnc process has stopped, return code: {}.".format(returncode)})
self.project.emit("log.error", {"message": "The vnc process has stopped, return code: {}.".format(returncode)})
@asyncio.coroutine
def _start_http(self):
@@ -570,6 +593,19 @@ class DockerVM(BaseNode):
])
self._telnet_servers.append((yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console)))
@asyncio.coroutine
def _window_size_changed_callback(self, columns, rows):
"""
Called when the console window size has been changed.
(when naws is enabled in the Telnet server)
:param columns: number of columns
:param rows: number of rows
"""
# resize the container TTY.
yield from self._manager.query("POST", "containers/{}/resize?h={}&w={}".format(self._cid, rows, columns))
@asyncio.coroutine
def _start_console(self):
"""
@@ -592,8 +628,7 @@ class DockerVM(BaseNode):
output_stream = asyncio.StreamReader()
input_stream = InputStream()
telnet = AsyncioTelnetServer(reader=output_stream, writer=input_stream, echo=True)
telnet = AsyncioTelnetServer(reader=output_stream, writer=input_stream, echo=True, naws=True, window_size_changed_callback=self._window_size_changed_callback)
try:
self._telnet_servers.append((yield from asyncio.start_server(telnet.run, self._manager.port_manager.console_host, self.console)))
except OSError as e:
@@ -603,7 +638,6 @@ class DockerVM(BaseNode):
input_stream.ws = self._console_websocket
output_stream.feed_data(self.name.encode() + b" console is now available... Press RETURN to get started.\r\n")
asyncio_ensure_future(self._read_console_output(self._console_websocket, output_stream))
@asyncio.coroutine
@@ -678,14 +712,15 @@ class DockerVM(BaseNode):
if state == "paused":
yield from self.unpause()
yield from self._fix_permissions()
if not self._permissions_fixed:
yield from self._fix_permissions()
state = yield from self._get_container_state()
if state != "stopped" or state != "exited":
# t=5 number of seconds to wait before killing the container
try:
yield from self.manager.query("POST", "containers/{}/stop".format(self._cid), params={"t": 5})
log.info("Docker container '{name}' [{image}] stopped".format(
name=self._name, image=self._image))
log.info("Docker container '{name}' [{image}] stopped".format(name=self._name, image=self._image))
except DockerHttp304Error:
# Container is already stopped
pass
@@ -725,12 +760,13 @@ class DockerVM(BaseNode):
if state == "paused" or state == "running":
yield from self.stop()
if self.console_type == "vnc":
if self._x11vnc_process:
if self._vnc_process:
try:
self._x11vnc_process.terminate()
yield from self._x11vnc_process.wait()
self._vnc_process.terminate()
yield from self._vnc_process.wait()
except ProcessLookupError:
pass
if self._xvfb_process:
try:
self._xvfb_process.terminate()
yield from self._xvfb_process.wait()
+10
View File
@@ -517,6 +517,16 @@ class IOUVM(BaseNode):
if "IOURC" not in os.environ:
env["IOURC"] = iourc_path
# create a symbolic link to the image to avoid IOU error "failed code signing checks"
# on newer images, see https://github.com/GNS3/gns3-server/issues/1484
try:
symlink = os.path.join(self.working_dir, os.path.basename(self.path))
if not os.path.islink(symlink):
os.symlink(self.path, symlink)
except OSError as e:
raise IOUError("Could not create symbolic link: {}".format(e))
command = yield from self._build_command()
try:
log.info("Starting IOU: {}".format(command))
+1 -1
View File
@@ -23,7 +23,7 @@ import logging
log = logging.getLogger(__name__)
# This ports are disallowed by Chrome and Firefox to avoid issues, we skip them as well
# These ports are disallowed by Chrome and Firefox to avoid issues, we skip them as well
BANNED_PORTS = set((1, 7, 9, 11, 13, 15, 17, 19, 20, 21, 22, 23, 25, 37, 42, 43, 53, 77, 79, 87, 95, 101, 102, 103,
104, 109, 110, 111, 113, 115, 117, 119, 123, 135, 139, 143, 179, 389, 465, 512, 513, 514, 515, 526,
530, 531, 532, 540, 556, 563, 587, 601, 636, 993, 995, 2049, 3659, 4045, 6000, 6665, 6666, 6667,
+6
View File
@@ -149,6 +149,7 @@ class VMware(BaseManager):
VIX 1.13 was the release for Player 6.
VIX 1.14 was the release for Player 7.
VIX 1.15 was the release for Workstation Player 12.
VIX 1.17 was the release for Workstation Player 14.
:param player_version: VMware Player major version.
"""
@@ -162,6 +163,8 @@ class VMware(BaseManager):
yield from self.check_vmrun_version(minimum_required_version="1.14.0")
elif player_version >= 12:
yield from self.check_vmrun_version(minimum_required_version="1.15.0")
elif player_version >= 14:
yield from self.check_vmrun_version(minimum_required_version="1.17.0")
self._host_type = "player"
@asyncio.coroutine
@@ -172,6 +175,7 @@ class VMware(BaseManager):
VIX 1.13 was the release for Workstation 10.
VIX 1.14 was the release for Workstation 11.
VIX 1.15 was the release for Workstation Pro 12.
VIX 1.17 was the release for Workstation Pro 14.
:param ws_version: VMware Workstation major version.
"""
@@ -185,6 +189,8 @@ class VMware(BaseManager):
yield from self.check_vmrun_version(minimum_required_version="1.14.0")
elif ws_version >= 12:
yield from self.check_vmrun_version(minimum_required_version="1.15.0")
elif ws_version >= 14:
yield from self.check_vmrun_version(minimum_required_version="1.17.0")
self._host_type = "ws"
@asyncio.coroutine
+1 -1
View File
@@ -315,7 +315,7 @@ class VPCSVM(BaseNode):
if sys.platform.startswith("win32"):
try:
self._process.send_signal(signal.CTRL_BREAK_EVENT)
except OSError:
except (SystemError, OSError):
pass
else:
try:
+7 -3
View File
@@ -446,9 +446,13 @@ class Compute:
self._capabilities = response.json
if response.json["version"].split("-")[0] != __version__.split("-")[0]:
msg = "GNS3 controller version {} is not the same as compute server {} version {}".format(__version__,
self._name,
response.json["version"])
if self._name.startswith("GNS3 VM"):
msg = "GNS3 version {} is not the same as the GNS3 VM version {}. Please upgrade the GNS3 VM.".format(__version__,
response.json["version"])
else:
msg = "GNS3 controller version {} is not the same as compute server {} version {}".format(__version__,
self._name,
response.json["version"])
if __version_info__[3] == 0:
# Stable release
log.error(msg)
+3 -3
View File
@@ -91,12 +91,12 @@ class Node:
# Update node properties with additional elements
for prop in kwargs:
if prop not in ignore_properties:
if prop and prop not in ignore_properties:
if hasattr(self, prop):
try:
setattr(self, prop, kwargs[prop])
except AttributeError as e:
log.critical("Can't set attribute %s", prop)
log.critical("Cannot set attribute '%s'".format(prop))
raise e
else:
if prop not in self.CONTROLLER_ONLY_PROPERTIES and kwargs[prop] is not None and kwargs[prop] != "":
@@ -254,7 +254,7 @@ class Node:
try:
self._width, self._height, filetype = self._project.controller.symbols.get_size(val)
except (ValueError, OSError) as e:
log.error("Could not write symbol: {}".format(e))
log.error("Could not set symbol: {}".format(e))
# If symbol is invalid we replace it by the default
self.symbol = ":/symbols/computer.svg"
if self._label is None:
+1 -1
View File
@@ -935,7 +935,7 @@ class Project:
with open(project_path, "rb") as f:
project = yield from import_project(self._controller, str(uuid.uuid4()), f, location=location, name=name, keep_compute_id=True)
except (ValueError, OSError, UnicodeEncodeError) as e:
raise aiohttp.web.HTTPConflict(text="Can not duplicate project: {}".format(str(e)))
raise aiohttp.web.HTTPConflict(text="Cannot duplicate project: {}".format(str(e)))
if previous_status == "closed":
yield from self.close()
+1 -1
View File
@@ -57,7 +57,7 @@ class CrashReport:
Report crash to a third party service
"""
DSN = "https://71472e2845b2422cab117bdfa8af55ec:da50c8f08b9f44d8b905356741c278df@sentry.io/38482"
DSN = "https://edb72a54588b4d04afc2de56b8cb5b24:7830885c8a2a4d0cb311de10ddfe3d27@sentry.io/38482"
if hasattr(sys, "frozen"):
cacert = get_resource("cacert.pem")
if cacert is not None and os.path.isfile(cacert):
@@ -263,10 +263,11 @@ class DockerHandler:
docker_manager = Docker.instance()
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
nio = container.ethernet_adapters[int(request.match_info["adapter_number"])].get_nio(0)
adapter_number = int(request.match_info["adapter_number"])
nio = container.ethernet_adapters[adapter_number].get_nio(0)
if "filters" in request.json and nio:
nio.filters = request.json["filters"]
yield from container.adapter_update_nio_binding(int(request.match_info["port_number"]), nio)
yield from container.adapter_update_nio_binding(adapter_number, nio)
response.set_status(201)
response.json(request.json)
@@ -301,12 +301,9 @@ class IOUHandler:
nio = vm.adapters[adapter_number].get_nio(port_number)
if "filters" in request.json and nio:
nio.filters = request.json["filters"]
yield from vm.adapter_update_nio_binding(
adapter_number,
port_number,
nio)
yield from vm.adapter_update_nio_binding(adapter_number, port_number, nio)
response.set_status(201)
response.json(nio)
response.json(request.json)
@Route.delete(
r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
@@ -42,9 +42,9 @@ class ServerHandler:
@Route.get(
r"/debug",
description="Return debug informations about the compute",
description="Return debug information about the compute",
status_codes={
201: "Writed"
201: "Written"
})
def debug(request, response):
response.content_type = "text/plain"
@@ -279,12 +279,13 @@ class VMwareHandler:
vmware_manager = VMware.instance()
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
nio = vm.ethernet_adapters[int(request.match_info["adapter_number"])]
adapter_number = int(request.match_info["adapter_number"])
nio = vm.ethernet_adapters[adapter_number]
if "filters" in request.json and nio:
nio.filters = request.json["filters"]
yield from vm.adapter_update_nio_binding(int(request.match_info["adapter_number"]), nio)
response.set_status(201)
response.json(request.json)
yield from vm.adapter_update_nio_binding(adapter_number, nio)
response.set_status(201)
response.json(request.json)
@Route.delete(
r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
@@ -59,7 +59,7 @@ class ComputeHandler:
@Route.put(
r"/computes/{compute_id}",
description="Get a compute server information",
description="Update a compute server",
status_codes={
200: "Compute server updated",
400: "Invalid request",
@@ -287,9 +287,9 @@ class ProjectHandler:
try:
with tempfile.TemporaryDirectory() as tmp_dir:
datas = yield from export_project(
project, tmp_dir,
include_images=bool(int(request.query.get("include_images", "0"))))
stream = yield from export_project(project,
tmp_dir,
include_images=bool(int(request.query.get("include_images", "0"))))
# We need to do that now because export could failed and raise an HTTP error
# that why response start need to be the later possible
response.content_type = 'application/gns3project'
@@ -297,7 +297,7 @@ class ProjectHandler:
response.enable_chunked_encoding()
yield from response.prepare(request)
for data in datas:
for data in stream:
response.write(data)
yield from response.drain()
@@ -139,7 +139,7 @@ class ServerHandler:
r"/debug",
description="Dump debug information to disk (debug directory in config directory). Work only for local server",
status_codes={
201: "Writed"
201: "Written"
})
def debug(request, response):
@@ -156,7 +156,7 @@ class ServerHandler:
f.write(ServerHandler._getDebugData())
except Exception as e:
# If something is wrong we log the info to the log and we hope the log will be include correctly to the debug export
log.error("Could not export debug informations {}".format(e), exc_info=1)
log.error("Could not export debug information {}".format(e), exc_info=1)
try:
if Controller.instance().gns3vm.engine == "vmware":
@@ -60,7 +60,7 @@ class SymbolHandler:
r"/symbols/{symbol_id:.+}/raw",
description="Write the symbol file",
status_codes={
200: "Symbol returned"
200: "Symbol written"
},
raw=True)
def upload(request, response):
@@ -78,6 +78,7 @@ class SymbolHandler:
f.write(chunk)
except (UnicodeEncodeError, 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)
+1 -1
View File
@@ -537,7 +537,7 @@ QEMU_OBJECT_SCHEMA = {
"description": "Console TCP port",
"minimum": 1,
"maximum": 65535,
"type": "integer"
"type": ["integer", "null"]
},
"console_type": {
"description": "Console type",
+16 -10
View File
@@ -15,7 +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 re
import asyncio
import asyncio.subprocess
import struct
@@ -62,10 +62,11 @@ READ_SIZE = 1024
class TelnetConnection(object):
"""Default implementation of telnet connection which may but may not be used."""
def __init__(self, reader, writer):
def __init__(self, reader, writer, window_size_changed_callback=None):
self.is_closing = False
self._reader = reader
self._writer = writer
self._window_size_changed_callback = window_size_changed_callback
@property
def reader(self):
@@ -85,10 +86,13 @@ class TelnetConnection(object):
"""Method called when client is disconnecting"""
pass
@asyncio.coroutine
def window_size_changed(self, columns, rows):
"""Method called when window size changed, only can occur when
`naws` flag is enable in server configuration."""
pass
if self._window_size_changed_callback:
yield from self._window_size_changed_callback(columns, rows)
@asyncio.coroutine
def feed(self, data):
@@ -116,7 +120,7 @@ class TelnetConnection(object):
class AsyncioTelnetServer:
MAX_NEGOTIATION_READ = 10
def __init__(self, reader=None, writer=None, binary=True, echo=False, naws=False, connection_factory=None):
def __init__(self, reader=None, writer=None, binary=True, echo=False, naws=False, window_size_changed_callback=None, connection_factory=None):
"""
Initializes telnet server
:param naws when True make a window size negotiation
@@ -131,6 +135,7 @@ class AsyncioTelnetServer:
self._lock = asyncio.Lock()
self._reader_process = None
self._current_read = None
self._window_size_changed_callback = window_size_changed_callback
self._binary = binary
# If echo is true when the client send data
@@ -139,8 +144,8 @@ class AsyncioTelnetServer:
self._echo = echo
self._naws = naws
def default_connection_factory(reader, writer):
return TelnetConnection(reader, writer)
def default_connection_factory(reader, writer, window_size_changed_callback):
return TelnetConnection(reader, writer, window_size_changed_callback)
if connection_factory is None:
connection_factory = default_connection_factory
@@ -190,7 +195,7 @@ class AsyncioTelnetServer:
@asyncio.coroutine
def run(self, network_reader, network_writer):
# Keep track of connected clients
connection = self._connection_factory(network_reader, network_writer)
connection = self._connection_factory(network_reader, network_writer, self._window_size_changed_callback)
self._connections[network_writer] = connection
try:
@@ -215,7 +220,7 @@ class AsyncioTelnetServer:
try:
writer.write_eof()
yield from writer.drain()
except ConnectionError:
except (AttributeError, ConnectionError):
continue
@asyncio.coroutine
@@ -307,6 +312,7 @@ class AsyncioTelnetServer:
cmd.append(buffer[location])
return op
@asyncio.coroutine
def _negotiate(self, data, connection):
""" Performs negotiation commands"""
@@ -314,7 +320,7 @@ class AsyncioTelnetServer:
if command == NAWS:
if len(payload) == 4:
columns, rows = struct.unpack(str('!HH'), bytes(payload))
connection.window_size_changed(columns, rows)
yield from connection.window_size_changed(columns, rows)
else:
log.warning('Wrong number of NAWS bytes')
else:
@@ -373,7 +379,7 @@ class AsyncioTelnetServer:
break
# SE command is followed by IAC, remove the last two operations from stack
self._negotiate(negotiation[0:-2], connection)
yield from self._negotiate(negotiation[0:-2], connection)
# This must be a 3-byte TELNET command
else:
+21 -8
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 re
import io
import struct
from xml.etree.ElementTree import ElementTree, ParseError
@@ -103,13 +104,21 @@ def get_size(data, default_width=0, default_height=0):
root = tree.getroot()
try:
width_attr = root.attrib.get("width", "0")
height_attr = root.attrib.get("height", "0")
width_attr = root.attrib.get("width", "100%")
height_attr = root.attrib.get("height", "100%")
if width_attr.endswith("%") or height_attr.endswith("%"):
# check to viewBox attribute if width or height value is a percentage
_, _, width_attr, height_attr = root.attrib.get("viewBox").split()
viewbox = root.attrib.get("viewBox")
if not viewbox:
raise ValueError("Invalid SVG file: missing viewBox attribute")
_, _, viewbox_width, viewbox_height = re.split(r'[\s,]+', viewbox)
if width_attr.endswith("%"):
width = _svg_convert_size(viewbox_width, width_attr)
else:
width = _svg_convert_size(width_attr)
if height_attr.endswith("%"):
height = _svg_convert_size(viewbox_height, height_attr)
else:
height = _svg_convert_size(height_attr)
except (AttributeError, IndexError) as e:
raise ValueError("Invalid SVG file: {}".format(e))
@@ -117,11 +126,12 @@ def get_size(data, default_width=0, default_height=0):
return width, height, filetype
def _svg_convert_size(size):
def _svg_convert_size(size, percent=None):
"""
Convert svg size to the px version
:param size: String with the size
:param percent: String with the percentage, None = 100%
"""
# https://www.w3.org/TR/SVG/coords.html#Units
@@ -133,8 +143,11 @@ def _svg_convert_size(size):
"in": 90,
"px": 1
}
if len(size) > 3:
factor = 1.0
if len(size) >= 3:
if size[-2:] in conversion_table:
return round(float(size[:-2]) * conversion_table[size[-2:]])
return round(float(size))
factor = conversion_table[size[-2:]]
size = size[:-2]
if percent:
factor *= float(percent.rstrip("%")) / 100.0
return round(float(size) * factor)
+2 -2
View File
@@ -23,8 +23,8 @@
# or negative for a release candidate or beta (after the base version
# number has been incremented)
__version__ = "2.1.10"
__version_info__ = (2, 1, 10, 0)
__version__ = "2.1.12"
__version_info__ = (2, 1, 12, 0)
# If it's a git checkout try to add the commit
if "dev" in __version__:
+2 -3
View File
@@ -971,13 +971,12 @@ def test_mount_binds(vm, tmpdir):
def test_start_vnc(vm, loop):
vm.console_resolution = "1280x1024"
with patch("shutil.which", return_value="/bin/x"):
with patch("shutil.which", return_value="/bin/Xtigervnc"):
with asyncio_patch("gns3server.compute.docker.docker_vm.wait_for_file_creation") as mock_wait:
with asyncio_patch("asyncio.create_subprocess_exec") as mock_exec:
loop.run_until_complete(asyncio.ensure_future(vm._start_vnc()))
assert vm._display is not None
mock_exec.assert_any_call("Xvfb", "-nolisten", "tcp", ":{}".format(vm._display), "-screen", "0", "1280x1024x16")
mock_exec.assert_any_call("x11vnc", "-forever", "-nopw", "-shared", "-geometry", "1280x1024", "-display", "WAIT:{}".format(vm._display), "-rfbport", str(vm.console), "-rfbportv6", str(vm.console), "-noncache", "-listen", "127.0.0.1")
assert mock_exec.call_args[0] == ("Xtigervnc", "-geometry", vm.console_resolution, "-depth", "16", "-interface", "127.0.0.1", "-rfbport", str(vm.console), "-AlwaysShared", "-SecurityTypes", "None", ":{}".format(vm._display))
mock_wait.assert_called_with("/tmp/.X11-unix/X{}".format(vm._display))