diff --git a/.travis.yml b/.travis.yml index e4f308b5..940ad1db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,3 +30,4 @@ env: - PYTHON_VERSION=3.4 - PYTHON_VERSION=3.5 - PYTHON_VERSION=3.6 + - PYTHON_VERSION=3.7 diff --git a/CHANGELOG b/CHANGELOG index 46c1f91a..cd56eb79 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,13 @@ # Change Log +## 2.1.9 13/08/2018 + +* Fix some more problems with interface short names. Fixes https://github.com/GNS3/gns3-gui/issues/2562 +* Fix incorrect short port names in topology summary. Fixes https://github.com/GNS3/gns3-gui/issues/2562 +* Set lower process priority when computing idle-pc value on Windows. Ref #2522. +* Catch exception: ZIP does not support timestamps before 1980. Ref #1360. +* Sync appliances + ## 2.1.8 14/06/2018 * 'caplog.text()' syntax is deprecated, use 'caplog.text' property instead. diff --git a/gns3server/compute/base_node.py b/gns3server/compute/base_node.py index e7a95a26..859e58cd 100644 --- a/gns3server/compute/base_node.py +++ b/gns3server/compute/base_node.py @@ -29,7 +29,7 @@ import re from gns3server.utils.interfaces import interfaces from ..compute.port_manager import PortManager -from ..utils.asyncio import wait_run_in_executor, locked_coroutine +from ..utils.asyncio import wait_run_in_executor, locking from ..utils.asyncio.telnet_server import AsyncioTelnetServer from ..ubridge.hypervisor import Hypervisor from ..ubridge.ubridge_error import UbridgeError @@ -547,7 +547,8 @@ class BaseNode: except UbridgeError as e: raise UbridgeError("Error while sending command '{}': {}: {}".format(command, e, self._ubridge_hypervisor.read_stdout())) - @locked_coroutine + @locking + @asyncio.coroutine def _start_ubridge(self): """ Starts uBridge (handles connections to and from this node). diff --git a/gns3server/compute/docker/__init__.py b/gns3server/compute/docker/__init__.py index 8cccf254..53948a52 100644 --- a/gns3server/compute/docker/__init__.py +++ b/gns3server/compute/docker/__init__.py @@ -25,7 +25,7 @@ import asyncio import logging import aiohttp from gns3server.utils import parse_version -from gns3server.utils.asyncio import locked_coroutine +from gns3server.utils.asyncio import locking from gns3server.compute.base_manager import BaseManager from gns3server.compute.docker.docker_vm import DockerVM from gns3server.compute.docker.docker_error import DockerError, DockerHttp304Error, DockerHttp404Error @@ -187,7 +187,8 @@ class Docker(BaseManager): autoping=True) return connection - @locked_coroutine + @locking + @asyncio.coroutine def pull_image(self, image, progress_callback=None): """ Pulls an image from the Docker repository diff --git a/gns3server/compute/docker/docker_vm.py b/gns3server/compute/docker/docker_vm.py index daf88fab..b03e1329 100644 --- a/gns3server/compute/docker/docker_vm.py +++ b/gns3server/compute/docker/docker_vm.py @@ -28,7 +28,8 @@ import os from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer from gns3server.utils.asyncio.raw_command_server import AsyncioRawCommandServer -from gns3server.utils.asyncio import wait_for_file_creation, asyncio_ensure_future +from gns3server.utils.asyncio import wait_for_file_creation +from gns3server.utils.asyncio import asyncio_ensure_future from gns3server.utils.get_resource import get_resource from gns3server.ubridge.ubridge_error import UbridgeError, UbridgeNamespaceError diff --git a/gns3server/compute/dynamips/__init__.py b/gns3server/compute/dynamips/__init__.py index 6c8f416b..140c2af8 100644 --- a/gns3server/compute/dynamips/__init__.py +++ b/gns3server/compute/dynamips/__init__.py @@ -36,6 +36,7 @@ log = logging.getLogger(__name__) from gns3server.utils.interfaces import interfaces, is_interface_up from gns3server.utils.asyncio import wait_run_in_executor, asyncio_ensure_future from gns3server.utils import parse_version +from gns3server.utils.asyncio import asyncio_ensure_future from uuid import uuid4 from ..base_manager import BaseManager from ..port_manager import PortManager diff --git a/gns3server/compute/iou/iou_vm.py b/gns3server/compute/iou/iou_vm.py index f396be87..f74f0aa8 100644 --- a/gns3server/compute/iou/iou_vm.py +++ b/gns3server/compute/iou/iou_vm.py @@ -43,7 +43,7 @@ from .utils.iou_export import nvram_export from gns3server.ubridge.ubridge_error import UbridgeError from gns3server.utils.file_watcher import FileWatcher from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer -from gns3server.utils.asyncio import locked_coroutine +from gns3server.utils.asyncio import locking import gns3server.utils.asyncio import gns3server.utils.images @@ -552,7 +552,8 @@ class IOUVM(BaseNode): # configure networking support yield from self._networking() - @locked_coroutine + @locking + @asyncio.coroutine def _networking(self): """ Configures the IOL bridge in uBridge. diff --git a/gns3server/compute/virtualbox/virtualbox_vm.py b/gns3server/compute/virtualbox/virtualbox_vm.py index 32645339..5a1038e0 100644 --- a/gns3server/compute/virtualbox/virtualbox_vm.py +++ b/gns3server/compute/virtualbox/virtualbox_vm.py @@ -33,7 +33,7 @@ import xml.etree.ElementTree as ET from gns3server.utils import parse_version from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer from gns3server.utils.asyncio.serial import asyncio_open_serial -from gns3server.utils.asyncio import locked_coroutine +from gns3server.utils.asyncio import locking from gns3server.compute.virtualbox.virtualbox_error import VirtualBoxError from gns3server.compute.nios.nio_udp import NIOUDP from gns3server.compute.adapters.ethernet_adapter import EthernetAdapter @@ -296,7 +296,8 @@ class VirtualBoxVM(BaseNode): if (yield from self.check_hw_virtualization()): self._hw_virtualization = True - @locked_coroutine + @locking + @asyncio.coroutine def stop(self): """ Stops this VirtualBox VM. diff --git a/gns3server/compute/vmware/__init__.py b/gns3server/compute/vmware/__init__.py index d41a48be..574826f4 100644 --- a/gns3server/compute/vmware/__init__.py +++ b/gns3server/compute/vmware/__init__.py @@ -32,6 +32,7 @@ import shlex from collections import OrderedDict from gns3server.utils.interfaces import interfaces from gns3server.utils.asyncio import subprocess_check_output +from gns3server.utils.asyncio import asyncio_ensure_future from gns3server.utils import parse_version log = logging.getLogger(__name__) diff --git a/gns3server/compute/vmware/vmware_vm.py b/gns3server/compute/vmware/vmware_vm.py index 69b85816..f4976678 100644 --- a/gns3server/compute/vmware/vmware_vm.py +++ b/gns3server/compute/vmware/vmware_vm.py @@ -26,7 +26,7 @@ import tempfile from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer from gns3server.utils.asyncio.serial import asyncio_open_serial -from gns3server.utils.asyncio import locked_coroutine +from gns3server.utils.asyncio import locking from collections import OrderedDict from .vmware_error import VMwareError from ..nios.nio_udp import NIOUDP @@ -94,7 +94,8 @@ class VMwareVM(BaseNode): return self._vmnets - @locked_coroutine + @locking + @asyncio.coroutine def _control_vm(self, subcommand, *additional_args): args = [self._vmx_path] diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index 3c2ad23e..319093f8 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -27,9 +27,9 @@ from operator import itemgetter from ..utils import parse_version from ..utils.images import list_images -from ..utils.asyncio import locked_coroutine, asyncio_ensure_future +from ..utils.asyncio import locking, asyncio_ensure_future from ..controller.controller_error import ControllerError -from ..version import __version__ +from ..version import __version__, __version_info__ import logging @@ -95,6 +95,7 @@ class Compute: self._set_auth(user, password) self._cpu_usage_percent = None self._memory_usage_percent = None + self._last_error = None self._capabilities = { "version": None, "node_types": [] @@ -137,6 +138,14 @@ class Compute: self._password = None self._auth = aiohttp.BasicAuth(self._user, "") + def set_last_error(self, msg): + """ + Set the last error message for this compute. + + :param msg: message + """ + self._last_error = msg + @asyncio.coroutine def interfaces(self): """ @@ -301,7 +310,8 @@ class Compute: "connected": self._connected, "cpu_usage_percent": self._cpu_usage_percent, "memory_usage_percent": self._memory_usage_percent, - "capabilities": self._capabilities + "capabilities": self._capabilities, + "last_error": self._last_error } @asyncio.coroutine @@ -398,7 +408,8 @@ class Compute: except aiohttp.web.HTTPConflict: pass - @locked_coroutine + @locking + @asyncio.coroutine def connect(self): """ Check if remote server is accessible @@ -420,7 +431,7 @@ class Compute: if self._connection_failure == 10: log.error("Could not connect to compute '{}' after multiple attempts: {}".format(self._id, e)) yield from self._controller.close_compute_projects(self) - asyncio.get_event_loop().call_later(2, lambda: asyncio_ensure_future(self._try_reconnect())) + asyncio.get_event_loop().call_later(2, lambda: asyncio.async(self._try_reconnect())) return except aiohttp.web.HTTPNotFound: raise aiohttp.web.HTTPConflict(text="The server {} is not a GNS3 server or it's a 1.X server".format(self._id)) @@ -432,16 +443,36 @@ class Compute: raise aiohttp.web.HTTPConflict(text="Invalid server url for server {}".format(self._id)) if "version" not in response.json: + msg = "The server {} is not a GNS3 server".format(self._id) + log.error(msg) self._http_session.close() - raise aiohttp.web.HTTPConflict(text="The server {} is not a GNS3 server".format(self._id)) + raise aiohttp.web.HTTPConflict(text=msg) self._capabilities = response.json - if parse_version(__version__)[:2] != parse_version(response.json["version"])[:2]: - self._http_session.close() - raise aiohttp.web.HTTPConflict(text="The server {} versions are not compatible {} != {}".format(self._id, __version__, response.json["version"])) + + 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 __version_info__[3] == 0: + # Stable release + log.error(msg) + self._http_session.close() + self._last_error = msg + raise aiohttp.web.HTTPConflict(text=msg) + elif parse_version(__version__)[:2] != parse_version(response.json["version"])[:2]: + # We don't allow different major version to interact even with dev build + log.error(msg) + self._http_session.close() + self._last_error = msg + raise aiohttp.web.HTTPConflict(text=msg) + else: + msg = "{}\nUsing different versions may result in unexpected problems. Please use at your own risk.".format(msg) + self._controller.notification.emit("log.warning", {"message": msg}) self._notifications = asyncio.gather(self._connect_notification()) self._connected = True self._connection_failure = 0 + self._last_error = None self._controller.notification.controller_emit("compute.updated", self.__json__()) @asyncio.coroutine diff --git a/gns3server/controller/export_project.py b/gns3server/controller/export_project.py index 326a0e31..c8725a5e 100644 --- a/gns3server/controller/export_project.py +++ b/gns3server/controller/export_project.py @@ -16,6 +16,7 @@ # along with this program. If not, see . import os +import sys import json import asyncio import aiohttp @@ -23,6 +24,7 @@ import zipfile import tempfile import zipstream +from datetime import datetime import logging log = logging.getLogger(__name__) @@ -77,6 +79,7 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id # ignore the .gns3 file if file.endswith(".gns3"): continue + _patch_mtime(path) zstream.write(path, os.path.relpath(path, project._path), compress_type=zipfile.ZIP_DEFLATED) # Export files from remote computes @@ -99,12 +102,29 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id f.write(data) response.close() f.close() + _patch_mtime(temp_path) zstream.write(temp_path, arcname=compute_file["path"], compress_type=zipfile.ZIP_DEFLATED) downloaded_files.add(compute_file['path']) return zstream +def _patch_mtime(path): + """ + Patch the file mtime because ZIP does not support timestamps before 1980 + + :param path: file path + """ + + if sys.platform.startswith("win"): + # only UNIX type platforms + return + st = os.stat(path) + file_date = datetime.fromtimestamp(st.st_mtime) + if file_date.year < 1980: + new_mtime = file_date.replace(year=1980).timestamp() + os.utime(path, (st.st_atime, new_mtime)) + def _is_exportable(path): """ :returns: True if file should not be included in the final archive @@ -228,6 +248,7 @@ def _export_local_image(image, zstream): if os.path.exists(path): arcname = os.path.join("images", directory, os.path.basename(image)) + _patch_mtime(path) zstream.write(path, arcname) return diff --git a/gns3server/controller/gns3vm/__init__.py b/gns3server/controller/gns3vm/__init__.py index 99567cfe..44fcf950 100644 --- a/gns3server/controller/gns3vm/__init__.py +++ b/gns3server/controller/gns3vm/__init__.py @@ -21,7 +21,7 @@ import asyncio import aiohttp import ipaddress -from ...utils.asyncio import locked_coroutine, asyncio_ensure_future +from ...utils.asyncio import locking, asyncio_ensure_future from .vmware_gns3_vm import VMwareGNS3VM from .virtualbox_gns3_vm import VirtualBoxGNS3VM from .hyperv_gns3_vm import HyperVGNS3VM @@ -278,13 +278,15 @@ class GNS3VM: except GNS3VMError as e: # User will receive the error later when they will try to use the node try: - yield from self._controller.add_compute(compute_id="vm", - name="GNS3 VM ({})".format(self.current_engine().vmname), - host=None, - force=True) + compute = yield from self._controller.add_compute(compute_id="vm", + name="GNS3 VM ({})".format(self.current_engine().vmname), + host=None, + force=True) + compute.set_last_error(str(e)) + except aiohttp.web.HTTPConflict: pass - log.error("Can't start the GNS3 VM: %s", str(e)) + log.error("Cannot start the GNS3 VM: {}".format(e)) @asyncio.coroutine def exit_vm(self): @@ -298,7 +300,8 @@ class GNS3VM: except GNS3VMError as e: log.warning(str(e)) - @locked_coroutine + @locking + @asyncio.coroutine def start(self): """ Start the GNS3 VM @@ -323,8 +326,9 @@ class GNS3VM: yield from engine.start() except Exception as e: yield from self._controller.delete_compute("vm") - log.error("Can't start the GNS3 VM: {}".format(str(e))) + log.error("Cannot start the GNS3 VM: {}".format(str(e))) yield from compute.update(name="GNS3 VM ({})".format(engine.vmname)) + compute.set_last_error(str(e)) raise e yield from compute.connect() # we can connect now that the VM has started yield from compute.update(name="GNS3 VM ({})".format(engine.vmname), @@ -370,8 +374,11 @@ class GNS3VM: self._controller.notification.controller_emit("log.warning", {"message": msg}) except ComputeError as e: log.warning("Could not check the VM is in the same subnet as the local server: {}".format(e)) + except aiohttp.web.HTTPConflict as e: + log.warning("Could not check the VM is in the same subnet as the local server: {}".format(e.text)) - @locked_coroutine + @locking + @asyncio.coroutine def _suspend(self): """ Suspend the GNS3 VM @@ -383,7 +390,8 @@ class GNS3VM: log.info("Suspend the GNS3 VM") yield from engine.suspend() - @locked_coroutine + @locking + @asyncio.coroutine def _stop(self): """ Stop the GNS3 VM diff --git a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py index f491e32f..ef1fba52 100644 --- a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py +++ b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py @@ -15,6 +15,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import sys import aiohttp import logging import asyncio @@ -107,7 +108,6 @@ class VirtualBoxGNS3VM(BaseGNS3VM): Check if the DHCP server associated with a vboxnet is enabled. :param vboxnet: vboxnet name - :returns: boolean """ @@ -125,6 +125,41 @@ class VirtualBoxGNS3VM(BaseGNS3VM): return True return False + @asyncio.coroutine + def _check_vboxnet_exists(self, vboxnet): + """ + Check if the vboxnet interface exists + + :param vboxnet: vboxnet name + :returns: boolean + """ + + properties = yield from self._execute("list", ["hostonlyifs"]) + for prop in properties.splitlines(): + try: + name, value = prop.split(':', 1) + except ValueError: + continue + if name.strip() == "Name" and value.strip() == vboxnet: + return True + return False + + @asyncio.coroutine + def _find_first_available_vboxnet(self): + """ + Find the first available vboxnet. + """ + + properties = yield from self._execute("list", ["hostonlyifs"]) + for prop in properties.splitlines(): + try: + name, value = prop.split(':', 1) + except ValueError: + continue + if name.strip() == "Name": + return value.strip() + return None + @asyncio.coroutine def _check_vbox_port_forwarding(self): """ @@ -158,18 +193,32 @@ class VirtualBoxGNS3VM(BaseGNS3VM): # get a NAT interface number nat_interface_number = yield from self._look_for_interface("nat") if nat_interface_number < 0: - raise GNS3VMError("The GNS3 VM: {} must have a NAT interface configured in order to start".format(self.vmname)) + raise GNS3VMError('VM "{}" must have a NAT interface configured in order to start'.format(self.vmname)) hostonly_interface_number = yield from self._look_for_interface("hostonly") if hostonly_interface_number < 0: - raise GNS3VMError("The GNS3 VM: {} must have a host only interface configured in order to start".format(self.vmname)) + raise GNS3VMError('VM "{}" must have a host-only interface configured in order to start'.format(self.vmname)) vboxnet = yield from self._look_for_vboxnet(hostonly_interface_number) if vboxnet is None: - raise GNS3VMError("VirtualBox host-only network could not be found for interface {} on GNS3 VM".format(hostonly_interface_number)) + raise GNS3VMError('A VirtualBox host-only network could not be found on network adapter {} for "{}"'.format(hostonly_interface_number, self._vmname)) + + if not (yield from self._check_vboxnet_exists(vboxnet)): + 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 = yield from 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)) + yield from self.set_hostonly_network(hostonly_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, + self._vmname)) if not (yield from self._check_dhcp_server(vboxnet)): - raise GNS3VMError("DHCP must be enabled on VirtualBox host-only network: {} for GNS3 VM".format(vboxnet)) + raise GNS3VMError('DHCP must be enabled on VirtualBox host-only network "{}"'.format(vboxnet)) vm_state = yield from self._get_state() log.info('"{}" state is {}'.format(self._vmname, vm_state)) @@ -311,3 +360,17 @@ class VirtualBoxGNS3VM(BaseGNS3VM): yield from self._execute("modifyvm", [self._vmname, "--memory", str(ram)], timeout=3) log.info("GNS3 VM RAM amount set to {}".format(ram)) + + @asyncio.coroutine + def set_hostonly_network(self, adapter_number, hostonly_network_name): + """ + Set a VirtualBox host-only network on a network adapter for the GNS3 VM. + + :param adapter_number: network adapter number + :param hostonly_network_name: name of the VirtualBox host-only network + """ + + yield from self._execute("modifyvm", [self._vmname, "--hostonlyadapter{}".format(adapter_number), hostonly_network_name], timeout=3) + log.info('VirtualBox host-only network "{}" set on network adapter {} for "{}"'.format(hostonly_network_name, + adapter_number, + self._vmname)) diff --git a/gns3server/controller/ports/atm_port.py b/gns3server/controller/ports/atm_port.py index 51da8d86..f63b9e4b 100644 --- a/gns3server/controller/ports/atm_port.py +++ b/gns3server/controller/ports/atm_port.py @@ -33,8 +33,8 @@ class ATMPort(SerialPort): """ return "ATM" - @property - def short_name_type(self): + @staticmethod + def short_name_type(): """ Returns the short name type for this port. @@ -42,10 +42,6 @@ class ATMPort(SerialPort): """ return "a" - @property - def short_name(self): - return "{}".format(self._port_number) - @property def data_link_types(self): """ diff --git a/gns3server/controller/ports/ethernet_port.py b/gns3server/controller/ports/ethernet_port.py index 6847998b..ae3f7e73 100644 --- a/gns3server/controller/ports/ethernet_port.py +++ b/gns3server/controller/ports/ethernet_port.py @@ -39,8 +39,8 @@ class EthernetPort(Port): return "Ethernet" - @property - def short_name_type(self): + @staticmethod + def short_name_type(): """ Returns the short name type for this port. diff --git a/gns3server/controller/ports/fastethernet_port.py b/gns3server/controller/ports/fastethernet_port.py index a8f98780..2a01e14a 100644 --- a/gns3server/controller/ports/fastethernet_port.py +++ b/gns3server/controller/ports/fastethernet_port.py @@ -34,8 +34,8 @@ class FastEthernetPort(Port): return "FastEthernet" - @property - def short_name_type(self): + @staticmethod + def short_name_type(): """ Returns the short name type for this port. diff --git a/gns3server/controller/ports/frame_relay_port.py b/gns3server/controller/ports/frame_relay_port.py index 356c13bd..87049917 100644 --- a/gns3server/controller/ports/frame_relay_port.py +++ b/gns3server/controller/ports/frame_relay_port.py @@ -34,10 +34,6 @@ class FrameRelayPort(SerialPort): return "FrameRelay" - @property - def short_name(self): - return "{}".format(self._port_number) - @property def data_link_types(self): """ diff --git a/gns3server/controller/ports/gigabitethernet_port.py b/gns3server/controller/ports/gigabitethernet_port.py index c96b820f..bcf7b143 100644 --- a/gns3server/controller/ports/gigabitethernet_port.py +++ b/gns3server/controller/ports/gigabitethernet_port.py @@ -34,8 +34,8 @@ class GigabitEthernetPort(Port): return "GigabitEthernet" - @property - def short_name_type(self): + @staticmethod + def short_name_type(): """ Returns the short name type for this port. diff --git a/gns3server/controller/ports/port.py b/gns3server/controller/ports/port.py index 4fc32720..601e8024 100644 --- a/gns3server/controller/ports/port.py +++ b/gns3server/controller/ports/port.py @@ -85,9 +85,9 @@ class Port: if self._short_name: return self._short_name elif '/' in self._name: - return self._name.replace(self.long_name_type(), self.short_name_type) + return self._name.replace(self.long_name_type(), self.short_name_type()) elif self._name.startswith("{}{}".format(self.long_name_type(), self._interface_number)): - return self.short_name_type + "{}".format(self._interface_number) + return self.short_name_type() + "{}".format(self._interface_number) return self._name @short_name.setter diff --git a/gns3server/controller/ports/port_factory.py b/gns3server/controller/ports/port_factory.py index 533676af..4cf06d11 100644 --- a/gns3server/controller/ports/port_factory.py +++ b/gns3server/controller/ports/port_factory.py @@ -209,7 +209,7 @@ class DynamipsPortFactory: for port_number in range(0, cls.ADAPTER_MATRIX[properties[name]]["nb_ports"]): name = "{}{}/{}".format(port_class.long_name_type(), adapter_number, port_number) port = port_class(name, adapter_number, adapter_number, port_number) - port.short_name = "{}{}/{}".format(port.short_name_type, adapter_number, port_number) + port.short_name = "{}{}/{}".format(port_class.short_name_type(), adapter_number, port_number) ports.append(port) adapter_number += 1 elif name.startswith("wic") and properties[name]: @@ -218,7 +218,7 @@ class DynamipsPortFactory: for port_number in range(0, cls.WIC_MATRIX[properties[name]]["nb_ports"]): name = "{}{}/{}".format(port_class.long_name_type(), 0, display_wic_port_number) port = port_class(name, 0, 0, wic_port_number) - port.short_name = "{}{}/{}".format(port.short_name_type, 0, display_wic_port_number) + port.short_name = "{}{}/{}".format(port_class.short_name_type(), 0, display_wic_port_number) ports.append(port) display_wic_port_number += 1 wic_port_number += 1 diff --git a/gns3server/controller/ports/pos_port.py b/gns3server/controller/ports/pos_port.py index 152e1f62..bd6a508e 100644 --- a/gns3server/controller/ports/pos_port.py +++ b/gns3server/controller/ports/pos_port.py @@ -33,8 +33,8 @@ class POSPort(SerialPort): """ return "POS" - @property - def short_name_type(self): + @staticmethod + def short_name_type(): """ Returns the short name type for this port. diff --git a/gns3server/controller/ports/serial_port.py b/gns3server/controller/ports/serial_port.py index 090f3a47..37fb4ebc 100644 --- a/gns3server/controller/ports/serial_port.py +++ b/gns3server/controller/ports/serial_port.py @@ -34,8 +34,8 @@ class SerialPort(Port): return "Serial" - @property - def short_name_type(self): + @staticmethod + def short_name_type(): """ Returns the short name type for this port. diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index 02d864d5..452bf8da 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -36,8 +36,9 @@ from .udp_link import UDPLink from ..config import Config from ..utils.path import check_path_allowed, get_default_project_directory from ..utils.asyncio.pool import Pool -from ..utils.asyncio import locked_coroutine, asyncio_ensure_future +from ..utils.asyncio import locking from ..utils.asyncio import wait_run_in_executor +from ..utils.asyncio import asyncio_ensure_future from .export_project import export_project from .import_project import import_project @@ -524,7 +525,8 @@ class Project: self.dump() return node - @locked_coroutine + @locking + @asyncio.coroutine def __delete_node_links(self, node): """ Delete all link connected to this node. @@ -814,7 +816,8 @@ class Project: def _topology_file(self): return os.path.join(self.path, self._filename) - @locked_coroutine + @locking + @asyncio.coroutine def open(self): """ Load topology elements diff --git a/gns3server/controller/snapshot.py b/gns3server/controller/snapshot.py index 8ea0cb26..512e23f5 100644 --- a/gns3server/controller/snapshot.py +++ b/gns3server/controller/snapshot.py @@ -101,7 +101,7 @@ class Snapshot: with tempfile.TemporaryDirectory() as tmpdir: zipstream = yield from export_project(self._project, tmpdir, keep_compute_id=True, allow_all_nodes=True) yield from wait_run_in_executor(self._create_snapshot_file, zipstream) - except OSError as e: + except (ValueError, OSError, RuntimeError) as e: raise aiohttp.web.HTTPConflict(text="Could not create snapshot file '{}': {}".format(self.path, e)) @asyncio.coroutine diff --git a/gns3server/crash_report.py b/gns3server/crash_report.py index 14a5ed0f..93124e9e 100644 --- a/gns3server/crash_report.py +++ b/gns3server/crash_report.py @@ -57,7 +57,7 @@ class CrashReport: Report crash to a third party service """ - DSN = "sync+https://95d9ad01f98746c2b9dacb7399526440:1e2d320de7be49ebbdebf47caf5b47ff@sentry.io/38482" + DSN = "sync+https://56af21e241ed4c1894ebe17bf06b1cd1:6075f91067954267b51e90b9638a6fad@sentry.io/38482" if hasattr(sys, "frozen"): cacert = get_resource("cacert.pem") if cacert is not None and os.path.isfile(cacert): diff --git a/gns3server/handlers/api/controller/project_handler.py b/gns3server/handlers/api/controller/project_handler.py index a9e6525f..5f1e7b00 100644 --- a/gns3server/handlers/api/controller/project_handler.py +++ b/gns3server/handlers/api/controller/project_handler.py @@ -16,6 +16,7 @@ # along with this program. If not, see . import os +import sys import aiohttp import asyncio import tempfile @@ -27,6 +28,7 @@ from gns3server.controller.export_project import export_project from gns3server.config import Config from gns3server.utils.asyncio import asyncio_ensure_future + from gns3server.schemas.project import ( PROJECT_OBJECT_SCHEMA, PROJECT_UPDATE_SCHEMA, @@ -317,8 +319,8 @@ class ProjectHandler: yield from response.write_eof() # Will be raise if you have no space left or permission issue on your temporary directory # RuntimeError: something was wrong during the zip process - except (OSError, RuntimeError) as e: - raise aiohttp.web.HTTPNotFound(text="Can't export project: {}".format(str(e))) + except (ValueError, OSError, RuntimeError) as e: + raise aiohttp.web.HTTPNotFound(text="Cannot export project: {}".format(str(e))) @Route.post( r"/projects/{project_id}/import", @@ -347,14 +349,25 @@ class ProjectHandler: # We write the content to a temporary location and after we extract it all. # It could be more optimal to stream this but it is not implemented in Python. # Spooled means the file is temporary kept in memory until max_size is reached + # Cannot use tempfile.SpooledTemporaryFile(max_size=10000) in Python 3.7 due + # to a bug https://bugs.python.org/issue26175 try: - with tempfile.SpooledTemporaryFile(max_size=10000) as temp: - while True: - chunk = yield from request.content.read(1024) - if not chunk: - break - temp.write(chunk) - project = yield from import_project(controller, request.match_info["project_id"], temp, location=path, name=name) + if sys.version_info >= (3, 7) and sys.version_info < (3, 8): + with tempfile.TemporaryFile() as temp: + while True: + chunk = yield from request.content.read(1024) + if not chunk: + break + temp.write(chunk) + project = yield from import_project(controller, request.match_info["project_id"], temp, location=path, name=name) + else: + with tempfile.SpooledTemporaryFile(max_size=10000) as temp: + while True: + chunk = yield from request.content.read(1024) + if not chunk: + break + temp.write(chunk) + project = yield from import_project(controller, request.match_info["project_id"], temp, location=path, name=name) except OSError as e: raise aiohttp.web.HTTPInternalServerError(text="Could not import the project: {}".format(e)) diff --git a/gns3server/handlers/api/controller/server_handler.py b/gns3server/handlers/api/controller/server_handler.py index 5bc6d95c..62358c73 100644 --- a/gns3server/handlers/api/controller/server_handler.py +++ b/gns3server/handlers/api/controller/server_handler.py @@ -72,7 +72,10 @@ class ServerHandler: # then shutdown the server itself from gns3server.web.web_server import WebServer server = WebServer.instance() - asyncio_ensure_future(server.shutdown_server()) + try: + asyncio_ensure_future(server.shutdown_server()) + except asyncio.CancelledError: + pass response.set_status(201) @Route.get( @@ -127,6 +130,7 @@ class ServerHandler: return try: controller.settings = request.json + #controller.save() except (OSError, PermissionError) as e: raise HTTPConflict(text="Can't save the settings {}".format(str(e))) response.json(controller.settings) diff --git a/gns3server/schemas/compute.py b/gns3server/schemas/compute.py index 2e8d08bc..c1ea3362 100644 --- a/gns3server/schemas/compute.py +++ b/gns3server/schemas/compute.py @@ -104,6 +104,10 @@ COMPUTE_OBJECT_SCHEMA = { "maximum": 100, "minimum": 0 }, + "last_error": { + "description": "Last error on the compute", + "type": ["string", "null"] + }, "capabilities": CAPABILITIES_SCHEMA }, "additionalProperties": False, diff --git a/gns3server/schemas/qemu.py b/gns3server/schemas/qemu.py index 8da99160..23a6bad7 100644 --- a/gns3server/schemas/qemu.py +++ b/gns3server/schemas/qemu.py @@ -133,7 +133,7 @@ QEMU_CREATE_SCHEMA = { }, "boot_priority": { "description": "QEMU boot priority", - "enum": ["c", "d", "n", "cn", "cd"] + "enum": ["c", "d", "n", "cn", "cd", "dn", "dc", "nc", "nd"] }, "ram": { "description": "Amount of RAM in MB", @@ -319,7 +319,7 @@ QEMU_UPDATE_SCHEMA = { }, "boot_priority": { "description": "QEMU boot priority", - "enum": ["c", "d", "n", "cn", "cd"] + "enum": ["c", "d", "n", "cn", "cd", "dn", "dc", "nc", "nd"] }, "ram": { "description": "Amount of RAM in MB", @@ -504,7 +504,7 @@ QEMU_OBJECT_SCHEMA = { }, "boot_priority": { "description": "QEMU boot priority", - "enum": ["c", "d", "n", "cn", "cd"] + "enum": ["c", "d", "n", "cn", "cd", "dn", "dc", "nc", "nd"] }, "node_directory": { "description": "Path to the VM working directory", diff --git a/gns3server/ubridge/ubridge_hypervisor.py b/gns3server/ubridge/ubridge_hypervisor.py index b32e2233..026045c4 100644 --- a/gns3server/ubridge/ubridge_hypervisor.py +++ b/gns3server/ubridge/ubridge_hypervisor.py @@ -20,7 +20,7 @@ import time import logging import asyncio -from ..utils.asyncio import locked_coroutine +from ..utils.asyncio import locking from .ubridge_error import UbridgeError log = logging.getLogger(__name__) @@ -176,7 +176,8 @@ class UBridgeHypervisor: self._host = host - @locked_coroutine + @locking + @asyncio.coroutine def send(self, command): """ Sends commands to this hypervisor. diff --git a/gns3server/utils/asyncio/__init__.py b/gns3server/utils/asyncio/__init__.py index 78c84a90..7ed4528d 100644 --- a/gns3server/utils/asyncio/__init__.py +++ b/gns3server/utils/asyncio/__init__.py @@ -160,32 +160,32 @@ def wait_for_named_pipe_creation(pipe_path, timeout=60): return raise asyncio.TimeoutError() +#FIXME: Use the following wrapper when we drop Python 3.4 and use the async def syntax +# def locking(f): +# +# @wraps(f) +# async def wrapper(oself, *args, **kwargs): +# lock_name = "__" + f.__name__ + "_lock" +# if not hasattr(oself, lock_name): +# setattr(oself, lock_name, asyncio.Lock()) +# async with getattr(oself, lock_name): +# return await f(oself, *args, **kwargs) +# return wrapper -def locked_coroutine(f): - """ - Method decorator that replace asyncio.coroutine that guarantee - that this specific method of this class instance will not be - executed twice at the same time - """ - @asyncio.coroutine - def new_function(*args, **kwargs): +def locking(f): - # In the instance of the class we will store - # a lock has an attribute. - lock_var_name = "__" + f.__name__ + "_lock" - if not hasattr(args[0], lock_var_name): - setattr(args[0], lock_var_name, asyncio.Lock()) + @functools.wraps(f) + def wrapper(oself, *args, **kwargs): + lock_name = "__" + f.__name__ + "_lock" + if not hasattr(oself, lock_name): + setattr(oself, lock_name, asyncio.Lock()) + with (yield from getattr(oself, lock_name)): + return (yield from f(oself, *args, **kwargs)) + return wrapper - with (yield from getattr(args[0], lock_var_name)): - return (yield from f(*args, **kwargs)) - - return new_function - - -# It's conservative approach to supported versions, please remove it when we drop the support to Python < 3.4.4 -if hasattr(asyncio, 'ensure_future'): - # python>=3.4.4 +#FIXME: conservative approach to supported versions, please remove it when we drop the support to Python < 3.4.4 +try: + from asyncio import ensure_future asyncio_ensure_future = asyncio.ensure_future -else: - # deprecated - asyncio_ensure_future = asyncio.async +except ImportError: + asyncio_ensure_future = getattr(asyncio, 'async') diff --git a/gns3server/utils/asyncio/telnet_server.py b/gns3server/utils/asyncio/telnet_server.py index 1e16d794..604ab914 100644 --- a/gns3server/utils/asyncio/telnet_server.py +++ b/gns3server/utils/asyncio/telnet_server.py @@ -214,9 +214,12 @@ class AsyncioTelnetServer: @asyncio.coroutine def close(self): for writer, connection in self._connections.items(): - writer.write_eof() - yield from writer.drain() - + try: + writer.write_eof() + yield from writer.drain() + except ConnectionResetError: + continue + @asyncio.coroutine def client_connected_hook(self): pass @@ -319,6 +322,7 @@ class AsyncioTelnetServer: else: log.debug("Not supported negotiation sequence, received {} bytes", len(data)) + @asyncio.coroutine def _IAC_parser(self, buf, network_reader, network_writer, connection): """ Processes and removes any Telnet commands from the buffer. @@ -421,9 +425,9 @@ if __name__ == '__main__': loop = asyncio.get_event_loop() process = loop.run_until_complete(asyncio_ensure_future(asyncio.subprocess.create_subprocess_exec("/bin/sh", "-i", - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.STDOUT, - stdin=asyncio.subprocess.PIPE))) + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.STDOUT, + stdin=asyncio.subprocess.PIPE))) server = AsyncioTelnetServer(reader=process.stdout, writer=process.stdin, binary=False, echo=False) coro = asyncio.start_server(server.run, '127.0.0.1', 4444, loop=loop) diff --git a/gns3server/web/web_server.py b/gns3server/web/web_server.py index 5c9b3248..ab6d1ab8 100644 --- a/gns3server/web/web_server.py +++ b/gns3server/web/web_server.py @@ -36,8 +36,7 @@ from ..compute import MODULES from ..compute.port_manager import PortManager from ..compute.qemu import Qemu from ..controller import Controller - -from gns3server.utils.asyncio import asyncio_ensure_future +from ..utils.asyncio import asyncio_ensure_future # do not delete this import import gns3server.handlers @@ -139,7 +138,10 @@ class WebServer: def signal_handler(signame, *args): log.warning("Server has got signal {}, exiting...".format(signame)) - asyncio_ensure_future(self.shutdown_server()) + try: + asyncio_ensure_future(self.shutdown_server()) + except asyncio.CancelledError: + pass signals = ["SIGTERM", "SIGINT"] if sys.platform.startswith("win"): @@ -304,4 +306,7 @@ class WebServer: log.warning("TypeError exception in the loop {}".format(e)) finally: if self._loop.is_running(): - self._loop.run_until_complete(self.shutdown_server()) + try: + self._loop.run_until_complete(self.shutdown_server()) + except asyncio.CancelledError: + pass diff --git a/tests/compute/docker/test_docker_vm.py b/tests/compute/docker/test_docker_vm.py index f51e8c9c..bb0e9779 100644 --- a/tests/compute/docker/test_docker_vm.py +++ b/tests/compute/docker/test_docker_vm.py @@ -87,7 +87,7 @@ def test_create(loop, project, manager): with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "ubuntu"}]) as mock_list_images: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu:latest") - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) mock.assert_called_with("POST", "containers/create", data={ "Tty": True, "OpenStdin": True, @@ -126,7 +126,7 @@ def test_create_with_tag(loop, project, manager): with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "ubuntu"}]) as mock_list_images: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu:16.04") - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) mock.assert_called_with("POST", "containers/create", data={ "Tty": True, "OpenStdin": True, @@ -168,7 +168,7 @@ def test_create_vnc(loop, project, manager): vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu", console_type="vnc", console=5900) vm._start_vnc = MagicMock() vm._display = 42 - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) mock.assert_called_with("POST", "containers/create", data={ "Tty": True, "OpenStdin": True, @@ -214,7 +214,7 @@ def test_create_with_extra_hosts(loop, project, manager): with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "ubuntu"}]): with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu", extra_hosts=extra_hosts) - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) called_kwargs = mock.call_args[1] assert "GNS3_EXTRA_HOSTS=199.199.199.1\ttest\n199.199.199.1\ttest2" in called_kwargs["data"]["Env"] assert vm._extra_hosts == extra_hosts @@ -232,7 +232,7 @@ def test_create_with_extra_hosts_wrong_format(loop, project, manager): with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response): vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu", extra_hosts=extra_hosts) with pytest.raises(DockerError): - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) def test_create_with_empty_extra_hosts(loop, project, manager): @@ -246,7 +246,7 @@ def test_create_with_empty_extra_hosts(loop, project, manager): with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "ubuntu"}]): with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu", extra_hosts=extra_hosts) - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) called_kwargs = mock.call_args[1] assert len([ e for e in called_kwargs["data"]["Env"] if "GNS3_EXTRA_HOSTS" in e]) == 0 @@ -266,7 +266,7 @@ def test_create_with_project_variables(loop, project, manager): with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "ubuntu"}]): with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu") - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) called_kwargs = mock.call_args[1] assert "VAR1=" in called_kwargs["data"]["Env"] assert "VAR2=VAL1" in called_kwargs["data"]["Env"] @@ -284,7 +284,7 @@ def test_create_start_cmd(loop, project, manager): with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu:latest") vm._start_command = "/bin/ls" - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) mock.assert_called_with("POST", "containers/create", data={ "Tty": True, "OpenStdin": True, @@ -328,7 +328,7 @@ def test_create_environment(loop, project, manager): with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu") vm.environment = "YES=1\nNO=0\nGNS3_MAX_ETHERNET=eth2" - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) assert mock.call_args[1]['data']['Env'] == [ "container=docker", "GNS3_MAX_ETHERNET=eth0", @@ -352,7 +352,7 @@ def test_create_environment_with_last_new_line_character(loop, project, manager) with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu") vm.environment = "YES=1\nNO=0\nGNS3_MAX_ETHERNET=eth2\n" - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) assert mock.call_args[1]['data']['Env'] == [ "container=docker", "GNS3_MAX_ETHERNET=eth0", @@ -385,7 +385,7 @@ def test_create_image_not_available(loop, project, manager): vm._get_image_information.side_effect = information with asyncio_patch("gns3server.compute.docker.DockerVM.pull_image", return_value=True) as mock_pull: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) mock.assert_called_with("POST", "containers/create", data={ "Tty": True, "OpenStdin": True, @@ -431,17 +431,17 @@ def test_get_container_state(loop, vm): } } with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: - assert loop.run_until_complete(asyncio.async(vm._get_container_state())) == "running" + assert loop.run_until_complete(asyncio.ensure_future(vm._get_container_state())) == "running" response["State"]["Running"] = False response["State"]["Paused"] = True with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: - assert loop.run_until_complete(asyncio.async(vm._get_container_state())) == "paused" + assert loop.run_until_complete(asyncio.ensure_future(vm._get_container_state())) == "paused" response["State"]["Running"] = False response["State"]["Paused"] = False with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: - assert loop.run_until_complete(asyncio.async(vm._get_container_state())) == "exited" + assert loop.run_until_complete(asyncio.ensure_future(vm._get_container_state())) == "exited" def test_is_running(loop, vm): @@ -452,17 +452,17 @@ def test_is_running(loop, vm): } } with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: - assert loop.run_until_complete(asyncio.async(vm.is_running())) is False + assert loop.run_until_complete(asyncio.ensure_future(vm.is_running())) is False response["State"]["Running"] = True with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: - assert loop.run_until_complete(asyncio.async(vm.is_running())) is True + assert loop.run_until_complete(asyncio.ensure_future(vm.is_running())) is True def test_pause(loop, vm): with asyncio_patch("gns3server.compute.docker.Docker.query") as mock: - loop.run_until_complete(asyncio.async(vm.pause())) + loop.run_until_complete(asyncio.ensure_future(vm.pause())) mock.assert_called_with("POST", "containers/e90e34656842/pause") assert vm.status == "suspended" @@ -471,7 +471,7 @@ def test_pause(loop, vm): def test_unpause(loop, vm): with asyncio_patch("gns3server.compute.docker.Docker.query") as mock: - loop.run_until_complete(asyncio.async(vm.unpause())) + loop.run_until_complete(asyncio.ensure_future(vm.unpause())) mock.assert_called_with("POST", "containers/e90e34656842/unpause") @@ -491,10 +491,10 @@ def test_start(loop, vm, manager, free_console_port): vm._start_console = AsyncioMagicMock() nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"}) - loop.run_until_complete(asyncio.async(vm.adapter_add_nio_binding(0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio))) with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) mock_query.assert_called_with("POST", "containers/e90e34656842/start") vm._add_ubridge_connection.assert_called_once_with(nio, 0) @@ -510,7 +510,7 @@ def test_start_namespace_failed(loop, vm, manager, free_console_port): vm.adapters = 1 nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"}) - loop.run_until_complete(asyncio.async(vm.adapter_add_nio_binding(0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio))) with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="stopped"): with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: @@ -520,7 +520,7 @@ def test_start_namespace_failed(loop, vm, manager, free_console_port): with asyncio_patch("gns3server.compute.docker.DockerVM._get_log", return_value='Hello not available') as mock_log: with pytest.raises(DockerError): - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) mock_query.assert_any_call("POST", "containers/e90e34656842/start") mock_add_ubridge_connection.assert_called_once_with(nio, 0) @@ -542,7 +542,7 @@ def test_start_without_nio(loop, vm, manager, free_console_port): with asyncio_patch("gns3server.compute.docker.DockerVM._get_namespace", return_value=42) as mock_namespace: with asyncio_patch("gns3server.compute.docker.DockerVM._add_ubridge_connection") as mock_add_ubridge_connection: with asyncio_patch("gns3server.compute.docker.DockerVM._start_console") as mock_start_console: - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) mock_query.assert_called_with("POST", "containers/e90e34656842/start") assert mock_add_ubridge_connection.called @@ -555,7 +555,7 @@ def test_start_unpause(loop, vm, manager, free_console_port): with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="paused"): with asyncio_patch("gns3server.compute.docker.DockerVM.unpause", return_value="paused") as mock: - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) assert mock.called assert vm.status == "started" @@ -563,7 +563,7 @@ def test_start_unpause(loop, vm, manager, free_console_port): def test_restart(loop, vm): with asyncio_patch("gns3server.compute.docker.Docker.query") as mock: - loop.run_until_complete(asyncio.async(vm.restart())) + loop.run_until_complete(asyncio.ensure_future(vm.restart())) mock.assert_called_with("POST", "containers/e90e34656842/restart") @@ -576,7 +576,7 @@ def test_stop(loop, vm): with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="running"): with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: - loop.run_until_complete(asyncio.async(vm.stop())) + loop.run_until_complete(asyncio.ensure_future(vm.stop())) mock_query.assert_called_with("POST", "containers/e90e34656842/stop", params={"t": 5}) assert mock.stop.called assert vm._ubridge_hypervisor is None @@ -588,7 +588,7 @@ def test_stop_paused_container(loop, vm): with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="paused"): with asyncio_patch("gns3server.compute.docker.DockerVM.unpause") as mock_unpause: with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: - loop.run_until_complete(asyncio.async(vm.stop())) + loop.run_until_complete(asyncio.ensure_future(vm.stop())) mock_query.assert_called_with("POST", "containers/e90e34656842/stop", params={"t": 5}) assert mock_unpause.called @@ -606,7 +606,7 @@ def test_update(loop, vm): with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "ubuntu"}]) as mock_list_images: with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="stopped"): with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock_query: - loop.run_until_complete(asyncio.async(vm.update())) + loop.run_until_complete(asyncio.ensure_future(vm.update())) mock_query.assert_any_call("DELETE", "containers/e90e34656842", params={"force": 1, "v": 1}) mock_query.assert_any_call("POST", "containers/create", data={ @@ -656,7 +656,7 @@ def test_update_vnc(loop, vm): with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "ubuntu"}]) as mock_list_images: with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="stopped"): with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock_query: - loop.run_until_complete(asyncio.async(vm.update())) + loop.run_until_complete(asyncio.ensure_future(vm.update())) assert vm.console == original_console assert vm.aux == original_aux @@ -675,7 +675,7 @@ def test_update_running(loop, vm): with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "ubuntu"}]) as mock_list_images: with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="running"): with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock_query: - loop.run_until_complete(asyncio.async(vm.update())) + loop.run_until_complete(asyncio.ensure_future(vm.update())) mock_query.assert_any_call("DELETE", "containers/e90e34656842", params={"force": 1, "v": 1}) mock_query.assert_any_call("POST", "containers/create", data={ @@ -713,7 +713,7 @@ def test_delete(loop, vm): with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="stopped"): with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: - loop.run_until_complete(asyncio.async(vm.delete())) + loop.run_until_complete(asyncio.ensure_future(vm.delete())) mock_query.assert_called_with("DELETE", "containers/e90e34656842", params={"force": 1, "v": 1}) @@ -723,11 +723,11 @@ def test_close(loop, vm, port_manager): "rport": 4343, "rhost": "127.0.0.1"} nio = vm.manager.create_nio(nio) - loop.run_until_complete(asyncio.async(vm.adapter_add_nio_binding(0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio))) with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="stopped"): with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: - loop.run_until_complete(asyncio.async(vm.close())) + loop.run_until_complete(asyncio.ensure_future(vm.close())) mock_query.assert_called_with("DELETE", "containers/e90e34656842", params={"force": 1, "v": 1}) assert vm._closed is True @@ -742,7 +742,7 @@ def test_close_vnc(loop, vm, port_manager): with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="stopped"): with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: - loop.run_until_complete(asyncio.async(vm.close())) + loop.run_until_complete(asyncio.ensure_future(vm.close())) mock_query.assert_called_with("DELETE", "containers/e90e34656842", params={"force": 1, "v": 1}) assert vm._closed is True @@ -756,7 +756,7 @@ def test_get_namespace(loop, vm): } } with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock_query: - assert loop.run_until_complete(asyncio.async(vm._get_namespace())) == 42 + assert loop.run_until_complete(asyncio.ensure_future(vm._get_namespace())) == 42 mock_query.assert_called_with("GET", "containers/e90e34656842/json") @@ -771,7 +771,7 @@ def test_add_ubridge_connection(loop, vm): vm._ubridge_hypervisor = MagicMock() vm._namespace = 42 - loop.run_until_complete(asyncio.async(vm._add_ubridge_connection(nio, 0))) + loop.run_until_complete(asyncio.ensure_future(vm._add_ubridge_connection(nio, 0))) calls = [ call.send('bridge create bridge0'), @@ -792,7 +792,7 @@ def test_add_ubridge_connection_none_nio(loop, vm): vm._ubridge_hypervisor = MagicMock() vm._namespace = 42 - loop.run_until_complete(asyncio.async(vm._add_ubridge_connection(nio, 0))) + loop.run_until_complete(asyncio.ensure_future(vm._add_ubridge_connection(nio, 0))) calls = [ call.send('bridge create bridge0'), @@ -813,7 +813,7 @@ def test_add_ubridge_connection_invalid_adapter_number(loop, vm): "rhost": "127.0.0.1"} nio = vm.manager.create_nio(nio) with pytest.raises(DockerError): - loop.run_until_complete(asyncio.async(vm._add_ubridge_connection(nio, 12))) + loop.run_until_complete(asyncio.ensure_future(vm._add_ubridge_connection(nio, 12))) def test_add_ubridge_connection_no_free_interface(loop, vm): @@ -829,7 +829,7 @@ def test_add_ubridge_connection_no_free_interface(loop, vm): interfaces = ["tap-gns3-e{}".format(index) for index in range(4096)] with patch("psutil.net_if_addrs", return_value=interfaces): - loop.run_until_complete(asyncio.async(vm._add_ubridge_connection(nio, 0))) + loop.run_until_complete(asyncio.ensure_future(vm._add_ubridge_connection(nio, 0))) def test_adapter_add_nio_binding(vm, loop): @@ -838,7 +838,7 @@ def test_adapter_add_nio_binding(vm, loop): "rport": 4343, "rhost": "127.0.0.1"} nio = vm.manager.create_nio(nio) - loop.run_until_complete(asyncio.async(vm.adapter_add_nio_binding(0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio))) assert vm._ethernet_adapters[0].get_nio(0) == nio @@ -853,9 +853,9 @@ def test_adapter_udpate_nio_binding(vm, loop): "rhost": "127.0.0.1"} nio = vm.manager.create_nio(nio) with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="running"): - loop.run_until_complete(asyncio.async(vm.adapter_add_nio_binding(0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio))) - loop.run_until_complete(asyncio.async(vm.adapter_update_nio_binding(0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_update_nio_binding(0, nio))) assert vm._ubridge_apply_filters.called @@ -867,9 +867,9 @@ def test_adapter_udpate_nio_binding_bridge_not_started(vm, loop): "rhost": "127.0.0.1"} nio = vm.manager.create_nio(nio) with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="running"): - loop.run_until_complete(asyncio.async(vm.adapter_add_nio_binding(0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio))) - loop.run_until_complete(asyncio.async(vm.adapter_update_nio_binding(0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_update_nio_binding(0, nio))) assert vm._ubridge_apply_filters.called is False @@ -880,7 +880,7 @@ def test_adapter_add_nio_binding_invalid_adapter(vm, loop): "rhost": "127.0.0.1"} nio = vm.manager.create_nio(nio) with pytest.raises(DockerError): - loop.run_until_complete(asyncio.async(vm.adapter_add_nio_binding(12, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(12, nio))) def test_adapter_remove_nio_binding(vm, loop): @@ -892,10 +892,10 @@ def test_adapter_remove_nio_binding(vm, loop): "rport": 4343, "rhost": "127.0.0.1"} nio = vm.manager.create_nio(nio) - loop.run_until_complete(asyncio.async(vm.adapter_add_nio_binding(0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio))) with asyncio_patch("gns3server.compute.docker.DockerVM._ubridge_send") as delete_ubridge_mock: - loop.run_until_complete(asyncio.async(vm.adapter_remove_nio_binding(0))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_remove_nio_binding(0))) assert vm._ethernet_adapters[0].get_nio(0) is None delete_ubridge_mock.assert_any_call('bridge stop bridge0') delete_ubridge_mock.assert_any_call('bridge remove_nio_udp bridge0 4242 127.0.0.1 4343') @@ -903,15 +903,15 @@ def test_adapter_remove_nio_binding(vm, loop): def test_adapter_remove_nio_binding_invalid_adapter(vm, loop): with pytest.raises(DockerError): - loop.run_until_complete(asyncio.async(vm.adapter_remove_nio_binding(12))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_remove_nio_binding(12))) def test_start_capture(vm, tmpdir, manager, free_console_port, loop): output_file = str(tmpdir / "test.pcap") nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"}) - loop.run_until_complete(asyncio.async(vm.adapter_add_nio_binding(0, nio))) - loop.run_until_complete(asyncio.async(vm.start_capture(0, output_file))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.start_capture(0, output_file))) assert vm._ethernet_adapters[0].get_nio(0).capturing @@ -919,10 +919,10 @@ def test_stop_capture(vm, tmpdir, manager, free_console_port, loop): output_file = str(tmpdir / "test.pcap") nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"}) - loop.run_until_complete(asyncio.async(vm.adapter_add_nio_binding(0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio))) loop.run_until_complete(vm.start_capture(0, output_file)) assert vm._ethernet_adapters[0].get_nio(0).capturing - loop.run_until_complete(asyncio.async(vm.stop_capture(0))) + loop.run_until_complete(asyncio.ensure_future(vm.stop_capture(0))) assert vm._ethernet_adapters[0].get_nio(0).capturing is False @@ -935,7 +935,7 @@ def test_get_log(loop, vm): mock_query.read = read with asyncio_patch("gns3server.compute.docker.Docker.http_query", return_value=mock_query) as mock: - images = loop.run_until_complete(asyncio.async(vm._get_log())) + images = loop.run_until_complete(asyncio.ensure_future(vm._get_log())) mock.assert_called_with("GET", "containers/e90e34656842/logs", params={"stderr": 1, "stdout": 1}, data={}) @@ -944,7 +944,7 @@ def test_get_image_informations(project, manager, loop): } with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu") - loop.run_until_complete(asyncio.async(vm._get_image_information())) + loop.run_until_complete(asyncio.ensure_future(vm._get_image_information())) mock.assert_called_with("GET", "images/ubuntu:latest/json") @@ -974,7 +974,7 @@ def test_start_vnc(vm, loop): with patch("shutil.which", return_value="/bin/x"): 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.async(vm._start_vnc())) + 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") @@ -983,13 +983,13 @@ def test_start_vnc(vm, loop): def test_start_vnc_xvfb_missing(vm, loop): with pytest.raises(DockerError): - loop.run_until_complete(asyncio.async(vm._start_vnc())) + loop.run_until_complete(asyncio.ensure_future(vm._start_vnc())) def test_start_aux(vm, loop): with asyncio_patch("asyncio.subprocess.create_subprocess_exec", return_value=MagicMock()) as mock_exec: - loop.run_until_complete(asyncio.async(vm._start_aux())) + loop.run_until_complete(asyncio.ensure_future(vm._start_aux())) mock_exec.assert_called_with('docker', 'exec', '-i', 'e90e34656842', '/gns3/bin/busybox', 'script', '-qfc', 'while true; do TERM=vt100 /gns3/bin/busybox sh; done', '/dev/null', stderr=asyncio.subprocess.STDOUT, stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE) @@ -1051,5 +1051,5 @@ def test_read_console_output_with_binary_mode(vm, loop): output_stream = MagicMock() with asyncio_patch('gns3server.compute.docker.docker_vm.DockerVM.stop'): - loop.run_until_complete(asyncio.async(vm._read_console_output(input_stream, output_stream))) + loop.run_until_complete(asyncio.ensure_future(vm._read_console_output(input_stream, output_stream))) output_stream.feed_data.assert_called_once_with(b"test") diff --git a/tests/compute/qemu/test_qemu_vm.py b/tests/compute/qemu/test_qemu_vm.py index 86ed8902..5d6c0326 100644 --- a/tests/compute/qemu/test_qemu_vm.py +++ b/tests/compute/qemu/test_qemu_vm.py @@ -166,9 +166,9 @@ def test_termination_callback(vm, async_run): async_run(vm._termination_callback(0)) assert vm.status == "stopped" - async_run(queue.get(0)) #  Ping + async_run(queue.get(1)) #  Ping - (action, event, kwargs) = async_run(queue.get(0)) + (action, event, kwargs) = async_run(queue.get(1)) assert action == "node.updated" assert event == vm @@ -186,7 +186,7 @@ def test_termination_callback_error(vm, tmpdir, async_run): async_run(vm._termination_callback(1)) assert vm.status == "stopped" - async_run(queue.get(0)) # Ping + async_run(queue.get(1)) # Ping (action, event, kwargs) = queue.get_nowait() assert action == "node.updated" diff --git a/tests/compute/test_project.py b/tests/compute/test_project.py index 32004c41..1dfdab16 100644 --- a/tests/compute/test_project.py +++ b/tests/compute/test_project.py @@ -210,5 +210,5 @@ def test_emit(async_run): def test_update_project(loop): variables = [{"name": "TEST", "value": "VAL"}] project = Project(project_id=str(uuid.uuid4())) - loop.run_until_complete(asyncio.async(project.update(variables=variables))) + loop.run_until_complete(asyncio.ensure_future(project.update(variables=variables))) assert project.variables == variables diff --git a/tests/compute/traceng/test_traceng_vm.py b/tests/compute/traceng/test_traceng_vm.py index bbf8df55..2f2133ef 100644 --- a/tests/compute/traceng/test_traceng_vm.py +++ b/tests/compute/traceng/test_traceng_vm.py @@ -56,7 +56,7 @@ def test_vm_invalid_traceng_path(vm, manager, loop): with pytest.raises(TraceNGError): nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) vm.port_add_nio_binding(0, nio) - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) assert vm.name == "test" assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0e" @@ -66,13 +66,13 @@ def test_start(loop, vm, async_run): process.returncode = None with NotificationManager.instance().queue() as queue: - async_run(queue.get(0)) # Ping + async_run(queue.get(1)) # Ping vm.ip_address = "192.168.1.1" with patch("sys.platform", return_value="win"): with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._check_requirements", return_value=True): with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec: - loop.run_until_complete(asyncio.async(vm.start("192.168.1.2"))) + loop.run_until_complete(asyncio.ensure_future(vm.start("192.168.1.2"))) assert mock_exec.call_args[0] == (vm._traceng_path(), '-u', '-c', @@ -88,7 +88,7 @@ def test_start(loop, vm, async_run): '192.168.1.2') assert vm.is_running() assert vm.command_line == ' '.join(mock_exec.call_args[0]) - (action, event, kwargs) = async_run(queue.get(0)) + (action, event, kwargs) = async_run(queue.get(1)) assert action == "node.updated" assert event == vm @@ -115,15 +115,15 @@ def test_stop(loop, vm, async_run): assert vm.is_running() with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"): - loop.run_until_complete(asyncio.async(vm.stop())) + loop.run_until_complete(asyncio.ensure_future(vm.stop())) assert vm.is_running() is False process.terminate.assert_called_with() - async_run(queue.get(0)) #  Ping - async_run(queue.get(0)) #  Started + async_run(queue.get(1)) #  Ping + async_run(queue.get(1)) #  Started - (action, event, kwargs) = async_run(queue.get(0)) + (action, event, kwargs) = async_run(queue.get(1)) assert action == "node.updated" assert event == vm @@ -175,5 +175,5 @@ def test_close(vm, port_manager, loop): with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._check_requirements", return_value=True): with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): vm.start() - loop.run_until_complete(asyncio.async(vm.close())) + loop.run_until_complete(asyncio.ensure_future(vm.close())) assert vm.is_running() is False diff --git a/tests/compute/vpcs/test_vpcs_vm.py b/tests/compute/vpcs/test_vpcs_vm.py index f7862516..238b1d52 100644 --- a/tests/compute/vpcs/test_vpcs_vm.py +++ b/tests/compute/vpcs/test_vpcs_vm.py @@ -91,7 +91,7 @@ def test_start(loop, vm, async_run): process.returncode = None with NotificationManager.instance().queue() as queue: - async_run(queue.get(0)) # Ping + async_run(queue.get(1)) # Ping with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True): with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec: @@ -113,7 +113,7 @@ def test_start(loop, vm, async_run): '127.0.0.1') assert vm.is_running() assert vm.command_line == ' '.join(mock_exec.call_args[0]) - (action, event, kwargs) = async_run(queue.get(0)) + (action, event, kwargs) = async_run(queue.get(1)) assert action == "node.updated" assert event == vm @@ -177,10 +177,10 @@ def test_stop(loop, vm, async_run): else: process.terminate.assert_called_with() - async_run(queue.get(0)) #  Ping - async_run(queue.get(0)) #  Started + async_run(queue.get(1)) #  Ping + async_run(queue.get(1)) #  Started - (action, event, kwargs) = async_run(queue.get(0)) + (action, event, kwargs) = async_run(queue.get(1)) assert action == "node.updated" assert event == vm diff --git a/tests/conftest.py b/tests/conftest.py index da83b431..0fcdd055 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -104,7 +104,7 @@ def http_server(request, loop, port_manager, monkeypatch, controller): monkeypatch.setattr('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.close', lambda self: True) loop.run_until_complete(instance.unload()) srv.close() - srv.wait_closed() + loop.run_until_complete(srv.wait_closed()) @pytest.fixture diff --git a/tests/controller/test_compute.py b/tests/controller/test_compute.py index aecf69e6..2a929872 100644 --- a/tests/controller/test_compute.py +++ b/tests/controller/test_compute.py @@ -277,6 +277,7 @@ def test_json(compute): "cpu_usage_percent": None, "memory_usage_percent": None, "connected": True, + "last_error": None, "capabilities": { "version": None, "node_types": [] diff --git a/tests/handlers/api/controller/test_compute.py b/tests/handlers/api/controller/test_compute.py index 57cbdfb7..36b3f5ac 100644 --- a/tests/handlers/api/controller/test_compute.py +++ b/tests/handlers/api/controller/test_compute.py @@ -131,6 +131,7 @@ def test_compute_list(http_controller, controller): 'name': 'My super server', 'cpu_usage_percent': None, 'memory_usage_percent': None, + 'last_error': None, 'capabilities': { 'version': None, 'node_types': [] diff --git a/tests/utils/test_asyncio.py b/tests/utils/test_asyncio.py index 942bf455..225cb9d6 100644 --- a/tests/utils/test_asyncio.py +++ b/tests/utils/test_asyncio.py @@ -21,7 +21,7 @@ import pytest import sys from unittest.mock import MagicMock -from gns3server.utils.asyncio import wait_run_in_executor, subprocess_check_output, wait_for_process_termination, locked_coroutine +from gns3server.utils.asyncio import wait_run_in_executor, subprocess_check_output, wait_for_process_termination, locking from tests.utils import AsyncioMagicMock @@ -84,7 +84,8 @@ def test_lock_decorator(loop): def __init__(self): self._test_val = 0 - @locked_coroutine + @locking + @asyncio.coroutine def method_to_lock(self): res = self._test_val yield from asyncio.sleep(0.1)