From 689a82a1808a75a09e16f2beafbe49b883ef5e8b Mon Sep 17 00:00:00 2001 From: ziajka Date: Mon, 13 Aug 2018 13:13:46 +0200 Subject: [PATCH 01/16] Release v2.1.9 --- CHANGELOG | 8 ++++++++ gns3server/crash_report.py | 2 +- gns3server/version.py | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) 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/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/version.py b/gns3server/version.py index 64c04b19..fd32e758 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,8 +23,8 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "2.1.8" -__version_info__ = (2, 1, 8, 0) +__version__ = "2.1.9" +__version_info__ = (2, 1, 9, 0) # If it's a git checkout try to add the commit if "dev" in __version__: From c593785c6d683bec055ae934279fec9b0d301bf6 Mon Sep 17 00:00:00 2001 From: ziajka Date: Mon, 13 Aug 2018 13:50:43 +0200 Subject: [PATCH 02/16] Development on 2.1.10dev1 --- gns3server/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gns3server/version.py b/gns3server/version.py index fd32e758..84c99de2 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,8 +23,8 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "2.1.9" -__version_info__ = (2, 1, 9, 0) +__version__ = "2.1.10dev1" +__version_info__ = (2, 1, 10, 99) # If it's a git checkout try to add the commit if "dev" in __version__: From aeb33024cad162165d5b030d3a239c4b4b7dc74a Mon Sep 17 00:00:00 2001 From: grossmj Date: Tue, 21 Aug 2018 17:49:58 +0700 Subject: [PATCH 03/16] Add missing Qemu boot priority values. Fixes https://github.com/GNS3/gns3-server/issues/1385 --- gns3server/schemas/qemu.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gns3server/schemas/qemu.py b/gns3server/schemas/qemu.py index f67f808a..d1157de9 100644 --- a/gns3server/schemas/qemu.py +++ b/gns3server/schemas/qemu.py @@ -131,7 +131,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", @@ -316,7 +316,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", @@ -500,7 +500,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", From 59ce105a50e289d408af71aaee2063288da72053 Mon Sep 17 00:00:00 2001 From: grossmj Date: Tue, 21 Aug 2018 19:46:14 +0700 Subject: [PATCH 04/16] Fix exception with short names for Dynamips interfaces. Fixes #1386. --- gns3server/controller/ports/atm_port.py | 8 ++------ gns3server/controller/ports/ethernet_port.py | 4 ++-- gns3server/controller/ports/fastethernet_port.py | 4 ++-- gns3server/controller/ports/frame_relay_port.py | 4 ---- gns3server/controller/ports/gigabitethernet_port.py | 4 ++-- gns3server/controller/ports/port.py | 4 ++-- gns3server/controller/ports/port_factory.py | 4 ++-- gns3server/controller/ports/pos_port.py | 4 ++-- gns3server/controller/ports/serial_port.py | 4 ++-- 9 files changed, 16 insertions(+), 24 deletions(-) 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 52b58530..2b7cadef 100644 --- a/gns3server/controller/ports/port.py +++ b/gns3server/controller/ports/port.py @@ -67,9 +67,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 88dfc569..35d66b41 100644 --- a/gns3server/controller/ports/port_factory.py +++ b/gns3server/controller/ports/port_factory.py @@ -191,7 +191,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]: @@ -200,7 +200,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. From 089d25c79d8abfc957243c7b4ffc6be9c077ada7 Mon Sep 17 00:00:00 2001 From: grossmj Date: Wed, 22 Aug 2018 16:54:43 +0700 Subject: [PATCH 05/16] Forbid controller and compute servers to be different versions. Report last compute server error to clients and display in the server summary. --- gns3server/controller/compute.py | 36 +++++++++++++++---- gns3server/controller/gns3vm/__init__.py | 2 ++ gns3server/schemas/compute.py | 4 +++ gns3server/version.py | 2 +- tests/controller/test_compute.py | 1 + tests/handlers/api/controller/test_compute.py | 1 + 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index c07eb8f7..da81b6e9 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -29,7 +29,7 @@ from ..utils import parse_version from ..utils.images import list_images from ..utils.asyncio import locked_coroutine 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": [] @@ -301,7 +302,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 @@ -404,7 +406,7 @@ class Compute: Check if remote server is accessible """ - if not self._connected and not self._closed: + if not self._connected and not self._closed and self.host: try: log.info("Connecting to compute '{}'".format(self._id)) response = yield from self._run_http_query("GET", "/capabilities") @@ -428,16 +430,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.emit("compute.updated", self.__json__()) @asyncio.coroutine diff --git a/gns3server/controller/gns3vm/__init__.py b/gns3server/controller/gns3vm/__init__.py index acd9f7c3..7f5dcd76 100644 --- a/gns3server/controller/gns3vm/__init__.py +++ b/gns3server/controller/gns3vm/__init__.py @@ -336,6 +336,8 @@ class GNS3VM: self._controller.notification.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 def _suspend(self): 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/version.py b/gns3server/version.py index 84c99de2..3d8ef14e 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,7 +23,7 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "2.1.10dev1" +__version__ = "2.1.10dev2" __version_info__ = (2, 1, 10, 99) # If it's a git checkout try to add the commit diff --git a/tests/controller/test_compute.py b/tests/controller/test_compute.py index 47840bc9..98b0aa18 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': [] From a3d1e865a8ff50919283f91bea8097875dde49d5 Mon Sep 17 00:00:00 2001 From: grossmj Date: Fri, 24 Aug 2018 18:52:15 +0700 Subject: [PATCH 06/16] Replace asyncio.async() by asyncio.ensure_future() in tests. Ref #2566. --- tests/compute/docker/test_docker.py | 16 +-- tests/compute/docker/test_docker_vm.py | 116 +++++++++--------- .../compute/dynamips/test_dynamips_router.py | 2 +- tests/compute/iou/test_iou_vm.py | 46 +++---- tests/compute/qemu/test_qcow2.py | 2 +- tests/compute/qemu/test_qemu_manager.py | 22 ++-- tests/compute/qemu/test_qemu_vm.py | 64 +++++----- tests/compute/test_base_node.py | 4 +- tests/compute/test_project.py | 12 +- tests/compute/traceng/test_traceng_vm.py | 8 +- .../virtualbox/test_virtualbox_manager.py | 2 +- .../compute/virtualbox/test_virtualbox_vm.py | 6 +- tests/compute/vmware/test_vmware_vm.py | 8 +- tests/compute/vpcs/test_vpcs_vm.py | 14 +-- tests/conftest.py | 2 +- tests/handlers/api/base.py | 4 +- tests/handlers/api/controller/test_link.py | 2 +- tests/handlers/api/controller/test_project.py | 2 +- tests/utils/test_asyncio.py | 10 +- 19 files changed, 171 insertions(+), 171 deletions(-) diff --git a/tests/compute/docker/test_docker.py b/tests/compute/docker/test_docker.py index db43c84c..b840fa83 100644 --- a/tests/compute/docker/test_docker.py +++ b/tests/compute/docker/test_docker.py @@ -45,7 +45,7 @@ def test_query_success(loop, vm): response.read.side_effect = read vm._session.request = AsyncioMagicMock(return_value=response) - data = loop.run_until_complete(asyncio.async(vm.query("POST", "test", data={"a": True}, params={"b": 1}))) + data = loop.run_until_complete(asyncio.ensure_future(vm.query("POST", "test", data={"a": True}, params={"b": 1}))) vm._session.request.assert_called_with('POST', 'http://docker/v1.25/test', data='{"a": true}', @@ -68,7 +68,7 @@ def test_query_error(loop, vm): response.read.side_effect = read vm._session.request = AsyncioMagicMock(return_value=response) with pytest.raises(DockerError): - data = loop.run_until_complete(asyncio.async(vm.query("POST", "test", data={"a": True}, params={"b": 1}))) + data = loop.run_until_complete(asyncio.ensure_future(vm.query("POST", "test", data={"a": True}, params={"b": 1}))) vm._session.request.assert_called_with('POST', 'http://docker/v1.25/test', data='{"a": true}', @@ -89,7 +89,7 @@ def test_query_error_json(loop, vm): response.read.side_effect = read vm._session.request = AsyncioMagicMock(return_value=response) with pytest.raises(DockerError): - data = loop.run_until_complete(asyncio.async(vm.query("POST", "test", data={"a": True}, params={"b": 1}))) + data = loop.run_until_complete(asyncio.ensure_future(vm.query("POST", "test", data={"a": True}, params={"b": 1}))) vm._session.request.assert_called_with('POST', 'http://docker/v1.25/test', data='{"a": true}', @@ -126,7 +126,7 @@ def test_list_images(loop): ] with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: - images = loop.run_until_complete(asyncio.async(Docker.instance().list_images())) + images = loop.run_until_complete(asyncio.ensure_future(Docker.instance().list_images())) mock.assert_called_with("GET", "images/json", params={"all": 0}) assert len(images) == 5 assert {"image": "ubuntu:12.04"} in images @@ -160,7 +160,7 @@ def test_pull_image(loop): with asyncio_patch("gns3server.compute.docker.Docker.query", side_effect=DockerHttp404Error("404")): with asyncio_patch("gns3server.compute.docker.Docker.http_query", return_value=mock_query) as mock: - images = loop.run_until_complete(asyncio.async(Docker.instance().pull_image("ubuntu"))) + images = loop.run_until_complete(asyncio.ensure_future(Docker.instance().pull_image("ubuntu"))) mock.assert_called_with("POST", "images/create", params={"fromImage": "ubuntu"}, timeout=None) @@ -174,7 +174,7 @@ def test_docker_check_connection_docker_minimum_version(vm, loop): asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response): vm._connected = False with pytest.raises(DockerError): - loop.run_until_complete(asyncio.async(vm._check_connection())) + loop.run_until_complete(asyncio.ensure_future(vm._check_connection())) def test_docker_check_connection_docker_preferred_version_against_newer(vm, loop): @@ -185,7 +185,7 @@ def test_docker_check_connection_docker_preferred_version_against_newer(vm, loop with patch("gns3server.compute.docker.Docker.connector"), \ asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response): vm._connected = False - loop.run_until_complete(asyncio.async(vm._check_connection())) + loop.run_until_complete(asyncio.ensure_future(vm._check_connection())) assert vm._api_version == DOCKER_PREFERRED_API_VERSION @@ -197,5 +197,5 @@ def test_docker_check_connection_docker_preferred_version_against_older(vm, loop with patch("gns3server.compute.docker.Docker.connector"), \ asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response): vm._connected = False - loop.run_until_complete(asyncio.async(vm._check_connection())) + loop.run_until_complete(asyncio.ensure_future(vm._check_connection())) assert vm._api_version == DOCKER_MINIMUM_API_VERSION \ No newline at end of file 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/dynamips/test_dynamips_router.py b/tests/compute/dynamips/test_dynamips_router.py index e3cf7fed..9c7e8425 100644 --- a/tests/compute/dynamips/test_dynamips_router.py +++ b/tests/compute/dynamips/test_dynamips_router.py @@ -70,6 +70,6 @@ def test_router_invalid_dynamips_path(project, manager, loop): with pytest.raises(DynamipsError): router = Router("test", "00010203-0405-0607-0809-0a0b0c0d0e0e", project, manager) - loop.run_until_complete(asyncio.async(router.create())) + loop.run_until_complete(asyncio.ensure_future(router.create())) assert router.name == "test" assert router.id == "00010203-0405-0607-0809-0a0b0c0d0e0e" diff --git a/tests/compute/iou/test_iou_vm.py b/tests/compute/iou/test_iou_vm.py index 24cf8bb7..afce2cf8 100644 --- a/tests/compute/iou/test_iou_vm.py +++ b/tests/compute/iou/test_iou_vm.py @@ -101,7 +101,7 @@ def test_start(loop, vm): with asyncio_patch("asyncio.create_subprocess_exec", return_value=mock_process) as mock_exec: mock_process.returncode = None - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) assert vm.is_running() assert vm.command_line == ' '.join(mock_exec.call_args[0]) @@ -129,7 +129,7 @@ def test_start_with_iourc(loop, vm, tmpdir): with patch("gns3server.config.Config.get_section_config", return_value={"iourc_path": fake_file}): with asyncio_patch("asyncio.create_subprocess_exec", return_value=mock_process) as exec_mock: mock_process.returncode = None - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) assert vm.is_running() arsgs, kwargs = exec_mock.call_args assert kwargs["env"]["IOURC"] == fake_file @@ -167,10 +167,10 @@ def test_stop(loop, vm): with asyncio_patch("asyncio.create_subprocess_exec", return_value=process): with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"): - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) process.returncode = None assert vm.is_running() - 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() @@ -192,9 +192,9 @@ def test_reload(loop, vm, fake_iou_bin): with asyncio_patch("asyncio.create_subprocess_exec", return_value=process): with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"): - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) assert vm.is_running() - loop.run_until_complete(asyncio.async(vm.reload())) + loop.run_until_complete(asyncio.ensure_future(vm.reload())) assert vm.is_running() is True process.terminate.assert_called_with() @@ -204,7 +204,7 @@ def test_close(vm, port_manager, loop): with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): vm.start() port = vm.console - loop.run_until_complete(asyncio.async(vm.close())) + loop.run_until_complete(asyncio.ensure_future(vm.close())) # Raise an exception if the port is not free port_manager.reserve_tcp_port(port, vm.project) assert vm.is_running() is False @@ -249,7 +249,7 @@ def test_create_netmap_config(vm): def test_build_command(vm, loop): - assert loop.run_until_complete(asyncio.async(vm._build_command())) == [vm.path, str(vm.application_id)] + assert loop.run_until_complete(asyncio.ensure_future(vm._build_command())) == [vm.path, str(vm.application_id)] def test_get_startup_config(vm): @@ -311,11 +311,11 @@ def test_library_check(loop, vm): with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="") as mock: - loop.run_until_complete(asyncio.async(vm._library_check())) + loop.run_until_complete(asyncio.ensure_future(vm._library_check())) with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="libssl => not found") as mock: with pytest.raises(IOUError): - loop.run_until_complete(asyncio.async(vm._library_check())) + loop.run_until_complete(asyncio.ensure_future(vm._library_check())) def test_enable_l1_keepalives(loop, vm): @@ -323,14 +323,14 @@ def test_enable_l1_keepalives(loop, vm): with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="***************************************************************\n\n-l Enable Layer 1 keepalive messages\n-u UDP port base for distributed networks\n") as mock: command = ["test"] - loop.run_until_complete(asyncio.async(vm._enable_l1_keepalives(command))) + loop.run_until_complete(asyncio.ensure_future(vm._enable_l1_keepalives(command))) assert command == ["test", "-l"] with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="***************************************************************\n\n-u UDP port base for distributed networks\n") as mock: command = ["test"] with pytest.raises(IOUError): - loop.run_until_complete(asyncio.async(vm._enable_l1_keepalives(command))) + loop.run_until_complete(asyncio.ensure_future(vm._enable_l1_keepalives(command))) assert command == ["test"] @@ -338,8 +338,8 @@ 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, 0, nio))) - loop.run_until_complete(asyncio.async(vm.start_capture(0, 0, output_file))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, 0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.start_capture(0, 0, output_file))) assert vm._adapters[0].get_nio(0).capturing @@ -347,10 +347,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, 0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, 0, nio))) loop.run_until_complete(vm.start_capture(0, 0, output_file)) assert vm._adapters[0].get_nio(0).capturing - loop.run_until_complete(asyncio.async(vm.stop_capture(0, 0))) + loop.run_until_complete(asyncio.ensure_future(vm.stop_capture(0, 0))) assert vm._adapters[0].get_nio(0).capturing is False @@ -363,42 +363,42 @@ def test_invalid_iou_file(loop, vm, iourc_file): hostname = socket.gethostname() - loop.run_until_complete(asyncio.async(vm._check_iou_licence())) + loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence())) # Missing ; with pytest.raises(IOUError): with open(iourc_file, "w+") as f: f.write("[license]\n{} = aaaaaaaaaaaaaaaa".format(hostname)) - loop.run_until_complete(asyncio.async(vm._check_iou_licence())) + loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence())) # Key too short with pytest.raises(IOUError): with open(iourc_file, "w+") as f: f.write("[license]\n{} = aaaaaaaaaaaaaa;".format(hostname)) - loop.run_until_complete(asyncio.async(vm._check_iou_licence())) + loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence())) # Invalid hostname with pytest.raises(IOUError): with open(iourc_file, "w+") as f: f.write("[license]\nbla = aaaaaaaaaaaaaa;") - loop.run_until_complete(asyncio.async(vm._check_iou_licence())) + loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence())) # Missing licence section with pytest.raises(IOUError): with open(iourc_file, "w+") as f: f.write("[licensetest]\n{} = aaaaaaaaaaaaaaaa;") - loop.run_until_complete(asyncio.async(vm._check_iou_licence())) + loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence())) # Broken config file with pytest.raises(IOUError): with open(iourc_file, "w+") as f: f.write("[") - loop.run_until_complete(asyncio.async(vm._check_iou_licence())) + loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence())) # Missing file with pytest.raises(IOUError): os.remove(iourc_file) - loop.run_until_complete(asyncio.async(vm._check_iou_licence())) + loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence())) def test_iourc_content(vm): diff --git a/tests/compute/qemu/test_qcow2.py b/tests/compute/qemu/test_qcow2.py index 39084872..bf09e584 100644 --- a/tests/compute/qemu/test_qcow2.py +++ b/tests/compute/qemu/test_qcow2.py @@ -69,5 +69,5 @@ def test_rebase(tmpdir, loop): qcow2 = Qcow2(str(tmpdir / "linked.qcow2")) assert qcow2.version == 3 assert qcow2.backing_file == "empty8G.qcow2" - loop.run_until_complete(asyncio.async(qcow2.rebase(qemu_img(), str(tmpdir / "empty16G.qcow2")))) + loop.run_until_complete(asyncio.ensure_future(qcow2.rebase(qemu_img(), str(tmpdir / "empty16G.qcow2")))) assert qcow2.backing_file == str(tmpdir / "empty16G.qcow2") diff --git a/tests/compute/qemu/test_qemu_manager.py b/tests/compute/qemu/test_qemu_manager.py index e0955556..163377e1 100644 --- a/tests/compute/qemu/test_qemu_manager.py +++ b/tests/compute/qemu/test_qemu_manager.py @@ -41,7 +41,7 @@ def fake_qemu_img_binary(tmpdir): def test_get_qemu_version(loop): with asyncio_patch("gns3server.compute.qemu.subprocess_check_output", return_value="QEMU emulator version 2.2.0, Copyright (c) 2003-2008 Fabrice Bellard") as mock: - version = loop.run_until_complete(asyncio.async(Qemu.get_qemu_version("/tmp/qemu-test"))) + version = loop.run_until_complete(asyncio.ensure_future(Qemu.get_qemu_version("/tmp/qemu-test"))) if sys.platform.startswith("win"): assert version == "" else: @@ -64,7 +64,7 @@ def test_binary_list(loop): else: version = "2.2.0" - qemus = loop.run_until_complete(asyncio.async(Qemu.binary_list())) + qemus = loop.run_until_complete(asyncio.ensure_future(Qemu.binary_list())) assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86"), "version": version} in qemus assert {"path": os.path.join(os.environ["PATH"], "qemu-kvm"), "version": version} in qemus @@ -72,14 +72,14 @@ def test_binary_list(loop): assert {"path": os.path.join(os.environ["PATH"], "hello"), "version": version} not in qemus assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86_64-spice"), "version": version} not in qemus - qemus = loop.run_until_complete(asyncio.async(Qemu.binary_list(["x86"]))) + qemus = loop.run_until_complete(asyncio.ensure_future(Qemu.binary_list(["x86"]))) assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86"), "version": version} in qemus assert {"path": os.path.join(os.environ["PATH"], "qemu-kvm"), "version": version} not in qemus assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x42"), "version": version} not in qemus assert {"path": os.path.join(os.environ["PATH"], "hello"), "version": version} not in qemus - qemus = loop.run_until_complete(asyncio.async(Qemu.binary_list(["x86", "x42"]))) + qemus = loop.run_until_complete(asyncio.ensure_future(Qemu.binary_list(["x86", "x42"]))) assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86"), "version": version} in qemus assert {"path": os.path.join(os.environ["PATH"], "qemu-kvm"), "version": version} not in qemus @@ -98,7 +98,7 @@ def test_img_binary_list(loop): os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) with asyncio_patch("gns3server.compute.qemu.subprocess_check_output", return_value="qemu-img version 2.2.0, Copyright (c) 2004-2008 Fabrice Bellard") as mock: - qemus = loop.run_until_complete(asyncio.async(Qemu.img_binary_list())) + qemus = loop.run_until_complete(asyncio.ensure_future(Qemu.img_binary_list())) version = "2.2.0" @@ -125,7 +125,7 @@ def test_create_image_abs_path(loop, tmpdir, fake_qemu_img_binary): "size": 100 } with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - loop.run_until_complete(asyncio.async(Qemu.instance().create_disk(fake_qemu_img_binary, str(tmpdir / "hda.qcow2"), options))) + loop.run_until_complete(asyncio.ensure_future(Qemu.instance().create_disk(fake_qemu_img_binary, str(tmpdir / "hda.qcow2"), options))) args, kwargs = process.call_args assert args == ( fake_qemu_img_binary, @@ -152,7 +152,7 @@ def test_create_image_relative_path(loop, tmpdir, fake_qemu_img_binary): } with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: with patch("gns3server.compute.qemu.Qemu.get_images_directory", return_value=str(tmpdir)): - loop.run_until_complete(asyncio.async(Qemu.instance().create_disk(fake_qemu_img_binary, "hda.qcow2", options))) + loop.run_until_complete(asyncio.ensure_future(Qemu.instance().create_disk(fake_qemu_img_binary, "hda.qcow2", options))) args, kwargs = process.call_args assert args == ( fake_qemu_img_binary, @@ -174,7 +174,7 @@ def test_create_image_exist(loop, tmpdir, fake_qemu_img_binary): with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: with patch("gns3server.compute.qemu.Qemu.get_images_directory", return_value=str(tmpdir)): with pytest.raises(QemuError): - loop.run_until_complete(asyncio.async(Qemu.instance().create_disk(fake_qemu_img_binary, "hda.qcow2", options))) + loop.run_until_complete(asyncio.ensure_future(Qemu.instance().create_disk(fake_qemu_img_binary, "hda.qcow2", options))) assert not process.called @@ -193,7 +193,7 @@ def test_create_image_with_not_supported_characters_by_filesystem(loop, tmpdir, patch("os.makedirs"): with pytest.raises(QemuError): - loop.run_until_complete(asyncio.async(Qemu.instance().create_disk( + loop.run_until_complete(asyncio.ensure_future(Qemu.instance().create_disk( fake_qemu_img_binary, "hda.qcow2", options))) assert not process.called @@ -201,12 +201,12 @@ def test_create_image_with_not_supported_characters_by_filesystem(loop, tmpdir, def test_get_kvm_archs_kvm_ok(loop): with patch("os.path.exists", return_value=True): - archs = loop.run_until_complete(asyncio.async(Qemu.get_kvm_archs())) + archs = loop.run_until_complete(asyncio.ensure_future(Qemu.get_kvm_archs())) if platform.machine() == 'x86_64': assert archs == ['x86_64', 'i386'] else: assert archs == [platform.machine()] with patch("os.path.exists", return_value=False): - archs = loop.run_until_complete(asyncio.async(Qemu.get_kvm_archs())) + archs = loop.run_until_complete(asyncio.ensure_future(Qemu.get_kvm_archs())) assert archs == [] diff --git a/tests/compute/qemu/test_qemu_vm.py b/tests/compute/qemu/test_qemu_vm.py index 0b4fc227..90347176 100644 --- a/tests/compute/qemu/test_qemu_vm.py +++ b/tests/compute/qemu/test_qemu_vm.py @@ -118,7 +118,7 @@ def test_is_running(vm, running_subprocess_mock): def test_start(loop, vm, running_subprocess_mock): with asyncio_patch("gns3server.compute.qemu.QemuVM.start_wrap_console"): with asyncio_patch("asyncio.create_subprocess_exec", return_value=running_subprocess_mock) as mock: - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) assert vm.is_running() assert vm.command_line == ' '.join(mock.call_args[0]) @@ -135,9 +135,9 @@ def test_stop(loop, vm, running_subprocess_mock): with asyncio_patch("asyncio.create_subprocess_exec", return_value=process): nio = Qemu.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) vm.adapter_add_nio_binding(0, nio) - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) assert vm.is_running() - 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() @@ -184,7 +184,7 @@ def test_termination_callback_error(vm, tmpdir, async_run): def test_reload(loop, vm): with asyncio_patch("gns3server.compute.qemu.QemuVM._control_vm") as mock: - loop.run_until_complete(asyncio.async(vm.reload())) + loop.run_until_complete(asyncio.ensure_future(vm.reload())) assert mock.called_with("system_reset") @@ -193,33 +193,33 @@ def test_suspend(loop, vm): control_vm_result = MagicMock() control_vm_result.match.group.decode.return_value = "running" with asyncio_patch("gns3server.compute.qemu.QemuVM._control_vm", return_value=control_vm_result) as mock: - loop.run_until_complete(asyncio.async(vm.suspend())) + loop.run_until_complete(asyncio.ensure_future(vm.suspend())) assert mock.called_with("system_reset") def test_add_nio_binding_udp(vm, loop): nio = Qemu.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}}) assert nio.lport == 4242 - 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 nio.lport == 4242 def test_port_remove_nio_binding(vm, loop): nio = Qemu.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}}) - loop.run_until_complete(asyncio.async(vm.adapter_add_nio_binding(0, nio))) - loop.run_until_complete(asyncio.async(vm.adapter_remove_nio_binding(0))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_remove_nio_binding(0))) assert vm._ethernet_adapters[0].ports[0] is None def test_close(vm, port_manager, loop): with asyncio_patch("gns3server.compute.qemu.QemuVM.start_wrap_console"): with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) console_port = vm.console - loop.run_until_complete(asyncio.async(vm.close())) + loop.run_until_complete(asyncio.ensure_future(vm.close())) # Raise an exception if the port is not free port_manager.reserve_tcp_port(console_port, vm.project) @@ -328,7 +328,7 @@ def test_disk_options(vm, tmpdir, loop, fake_qemu_img_binary): open(vm._hda_disk_image, "w+").close() with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - options = loop.run_until_complete(asyncio.async(vm._disk_options())) + options = loop.run_until_complete(asyncio.ensure_future(vm._disk_options())) assert process.called args, kwargs = process.call_args assert args == (fake_qemu_img_binary, "create", "-o", "backing_file={}".format(vm._hda_disk_image), "-f", "qcow2", os.path.join(vm.working_dir, "hda_disk.qcow2")) @@ -341,7 +341,7 @@ def test_cdrom_option(vm, tmpdir, loop, fake_qemu_img_binary): vm._cdrom_image = str(tmpdir / "test.iso") open(vm._cdrom_image, "w+").close() - options = loop.run_until_complete(asyncio.async(vm._build_command())) + options = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) assert ' '.join(['-cdrom', str(tmpdir / "test.iso")]) in ' '.join(options) @@ -351,7 +351,7 @@ def test_bios_option(vm, tmpdir, loop, fake_qemu_img_binary): vm._bios_image = str(tmpdir / "test.img") open(vm._bios_image, "w+").close() - options = loop.run_until_complete(asyncio.async(vm._build_command())) + options = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) assert ' '.join(['-bios', str(tmpdir / "test.img")]) in ' '.join(options) @@ -359,14 +359,14 @@ def test_bios_option(vm, tmpdir, loop, fake_qemu_img_binary): def test_vnc_option(vm, tmpdir, loop, fake_qemu_img_binary): vm._console_type = 'vnc' vm._console = 5905 - options = loop.run_until_complete(asyncio.async(vm._build_command())) + options = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) assert '-vnc 127.0.0.1:5' in ' '.join(options) def test_spice_option(vm, tmpdir, loop, fake_qemu_img_binary): vm._console_type = 'spice' vm._console = 5905 - options = loop.run_until_complete(asyncio.async(vm._build_command())) + options = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) assert '-spice addr=127.0.0.1,port=5905,disable-ticketing' in ' '.join(options) assert '-vga qxl' in ' '.join(options) @@ -383,7 +383,7 @@ def test_disk_options_multiple_disk(vm, tmpdir, loop, fake_qemu_img_binary): open(vm._hdd_disk_image, "w+").close() with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - options = loop.run_until_complete(asyncio.async(vm._disk_options())) + options = loop.run_until_complete(asyncio.ensure_future(vm._disk_options())) assert options == [ '-drive', 'file=' + os.path.join(vm.working_dir, "hda_disk.qcow2") + ',if=ide,index=0,media=disk', @@ -400,7 +400,7 @@ def test_set_process_priority(vm, loop, fake_qemu_img_binary): vm._process = MagicMock() vm._process.pid = 42 vm._process_priority = "low" - loop.run_until_complete(asyncio.async(vm._set_process_priority())) + loop.run_until_complete(asyncio.ensure_future(vm._set_process_priority())) assert process.called args, kwargs = process.call_args assert args == ("renice", "-n", "5", "-p", "42") @@ -412,7 +412,7 @@ def test_set_process_priority_normal(vm, loop, fake_qemu_img_binary): with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: vm._process = MagicMock() vm._process.pid = 42 - loop.run_until_complete(asyncio.async(vm._set_process_priority())) + loop.run_until_complete(asyncio.ensure_future(vm._set_process_priority())) assert not process.called @@ -429,7 +429,7 @@ def test_control_vm(vm, loop): reader = MagicMock() writer = MagicMock() with asyncio_patch("asyncio.open_connection", return_value=(reader, writer)) as open_connect: - res = loop.run_until_complete(asyncio.async(vm._control_vm("test"))) + res = loop.run_until_complete(asyncio.ensure_future(vm._control_vm("test"))) assert writer.write.called_with("test") assert res is None @@ -446,7 +446,7 @@ def test_control_vm_expect_text(vm, loop, running_subprocess_mock): reader.readline.return_value = future vm._monitor = 4242 - res = loop.run_until_complete(asyncio.async(vm._control_vm("test", [b"epic"]))) + res = loop.run_until_complete(asyncio.ensure_future(vm._control_vm("test", [b"epic"]))) assert writer.write.called_with("test") assert res == "epic product" @@ -456,7 +456,7 @@ def test_build_command(vm, loop, fake_qemu_binary, port_manager): os.environ["DISPLAY"] = "0:0" with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - cmd = loop.run_until_complete(asyncio.async(vm._build_command())) + cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) nio = vm._local_udp_tunnels[0][0] assert cmd == [ fake_qemu_binary, @@ -489,7 +489,7 @@ def test_build_command_manual_uuid(vm, loop, fake_qemu_binary, port_manager): vm.options = "-uuid e1c307a4-896f-11e6-81a5-3c07547807cc" os.environ["DISPLAY"] = "0:0" with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - cmd = loop.run_until_complete(asyncio.async(vm._build_command())) + cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) assert "e1c307a4-896f-11e6-81a5-3c07547807cc" in cmd assert vm.id not in cmd @@ -502,7 +502,7 @@ def test_build_command_kvm(linux_platform, vm, loop, fake_qemu_binary, port_mana vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.3.2") os.environ["DISPLAY"] = "0:0" with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - cmd = loop.run_until_complete(asyncio.async(vm._build_command())) + cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) nio = vm._local_udp_tunnels[0][0] assert cmd == [ fake_qemu_binary, @@ -536,7 +536,7 @@ def test_build_command_kvm_2_4(linux_platform, vm, loop, fake_qemu_binary, port_ vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.4.2") os.environ["DISPLAY"] = "0:0" with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - cmd = loop.run_until_complete(asyncio.async(vm._build_command())) + cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) nio = vm._local_udp_tunnels[0][0] assert cmd == [ fake_qemu_binary, @@ -569,7 +569,7 @@ def test_build_command_without_display(vm, loop, fake_qemu_binary): os.environ["DISPLAY"] = "" with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - cmd = loop.run_until_complete(asyncio.async(vm._build_command())) + cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) assert "-nographic" in cmd @@ -578,7 +578,7 @@ def test_build_command_two_adapters(vm, loop, fake_qemu_binary, port_manager): os.environ["DISPLAY"] = "0:0" vm.adapters = 2 with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - cmd = loop.run_until_complete(asyncio.async(vm._build_command())) + cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) nio1 = vm._local_udp_tunnels[0][0] nio2 = vm._local_udp_tunnels[1][0] assert cmd == [ @@ -619,7 +619,7 @@ def test_build_command_two_adapters_mac_address(vm, loop, fake_qemu_binary, port mac_1 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 1) assert mac_0[:8] == "00:00:ab" with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - cmd = loop.run_until_complete(asyncio.async(vm._build_command())) + cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) assert "e1000,mac={},netdev=gns3-0".format(mac_0) in cmd assert "e1000,mac={},netdev=gns3-1".format(mac_1) in cmd @@ -628,7 +628,7 @@ def test_build_command_two_adapters_mac_address(vm, loop, fake_qemu_binary, port mac_1 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 1) assert mac_0[:8] == "00:42:ab" with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - cmd = loop.run_until_complete(asyncio.async(vm._build_command())) + cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) assert "e1000,mac={},netdev=gns3-0".format(mac_0) in cmd assert "e1000,mac={},netdev=gns3-1".format(mac_1) in cmd @@ -648,7 +648,7 @@ def test_build_command_large_number_of_adapters(vm, loop, fake_qemu_binary, port mac_1 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 1) assert mac_0[:8] == "00:00:ab" with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - cmd = loop.run_until_complete(asyncio.async(vm._build_command())) + cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) # Count if we have 100 e1000 adapters in the command assert len([l for l in cmd if "e1000" in l ]) == 100 @@ -672,10 +672,10 @@ def test_build_command_large_number_of_adapters(vm, loop, fake_qemu_binary, port vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.0.0") with pytest.raises(QemuError): with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - cmd = loop.run_until_complete(asyncio.async(vm._build_command())) + cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) vm.adapters = 5 with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: - cmd = loop.run_until_complete(asyncio.async(vm._build_command())) + cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) # Windows accept this kind of mistake @@ -685,7 +685,7 @@ def test_build_command_with_invalid_options(vm, loop, fake_qemu_binary): vm.options = "'test" with pytest.raises(QemuError): - cmd = loop.run_until_complete(asyncio.async(vm._build_command())) + cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command())) def test_hda_disk_image(vm, images_dir): diff --git a/tests/compute/test_base_node.py b/tests/compute/test_base_node.py index cfc39872..4a61c5ad 100644 --- a/tests/compute/test_base_node.py +++ b/tests/compute/test_base_node.py @@ -83,7 +83,7 @@ def test_close(node, loop, port_manager): node.aux = aux port = node.console - assert loop.run_until_complete(asyncio.async(node.close())) + assert loop.run_until_complete(asyncio.ensure_future(node.close())) # Raise an exception if the port is not free port_manager.reserve_tcp_port(port, node.project) # Raise an exception if the port is not free @@ -92,7 +92,7 @@ def test_close(node, loop, port_manager): assert node.aux is None # Called twice closed should return False - assert loop.run_until_complete(asyncio.async(node.close())) is False + assert loop.run_until_complete(asyncio.ensure_future(node.close())) is False def test_aux(project, manager, port_manager): diff --git a/tests/compute/test_project.py b/tests/compute/test_project.py index 82493f8e..1dfdab16 100644 --- a/tests/compute/test_project.py +++ b/tests/compute/test_project.py @@ -43,7 +43,7 @@ def manager(port_manager): @pytest.fixture(scope="function") def node(project, manager, loop): node = manager.create_node("test", project.id, "00010203-0405-0607-0809-0a0b0c0d0e0f") - return loop.run_until_complete(asyncio.async(node)) + return loop.run_until_complete(asyncio.ensure_future(node)) def test_affect_uuid(): @@ -140,7 +140,7 @@ def test_project_delete(loop): project = Project(project_id=str(uuid4())) directory = project.path assert os.path.exists(directory) - loop.run_until_complete(asyncio.async(project.delete())) + loop.run_until_complete(asyncio.ensure_future(project.delete())) assert os.path.exists(directory) is False @@ -150,7 +150,7 @@ def test_project_delete_permission_issue(loop): assert os.path.exists(directory) os.chmod(directory, 0) with pytest.raises(aiohttp.web.HTTPInternalServerError): - loop.run_until_complete(asyncio.async(project.delete())) + loop.run_until_complete(asyncio.ensure_future(project.delete())) os.chmod(directory, 700) @@ -164,7 +164,7 @@ def test_project_add_node(manager): def test_project_close(loop, node, project): with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.close") as mock: - loop.run_until_complete(asyncio.async(project.close())) + loop.run_until_complete(asyncio.ensure_future(project.close())) assert mock.called assert node.id not in node.manager._nodes @@ -181,7 +181,7 @@ def test_list_files(tmpdir, loop): with open(os.path.join(path, "test.txt"), "w+") as f: f.write("test2") - files = loop.run_until_complete(asyncio.async(project.list_files())) + files = loop.run_until_complete(asyncio.ensure_future(project.list_files())) assert files == [ { @@ -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..974555fe 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" @@ -72,7 +72,7 @@ def test_start(loop, vm, async_run): 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', @@ -115,7 +115,7 @@ 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() @@ -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/virtualbox/test_virtualbox_manager.py b/tests/compute/virtualbox/test_virtualbox_manager.py index 097185e2..15d0ce4e 100644 --- a/tests/compute/virtualbox/test_virtualbox_manager.py +++ b/tests/compute/virtualbox/test_virtualbox_manager.py @@ -92,7 +92,7 @@ def test_list_vms(manager, loop): with asyncio_patch("gns3server.compute.virtualbox.VirtualBox.execute") as mock: mock.side_effect = execute_mock - vms = loop.run_until_complete(asyncio.async(manager.list_vms())) + vms = loop.run_until_complete(asyncio.ensure_future(manager.list_vms())) assert vms == [ {"vmname": "Windows 8.1", "ram": 512}, {"vmname": "Linux Microcore 4.7.1", "ram": 256} diff --git a/tests/compute/virtualbox/test_virtualbox_vm.py b/tests/compute/virtualbox/test_virtualbox_vm.py index 8e6e3136..e3e44525 100644 --- a/tests/compute/virtualbox/test_virtualbox_vm.py +++ b/tests/compute/virtualbox/test_virtualbox_vm.py @@ -75,20 +75,20 @@ def test_rename_vmname(project, manager, async_run): def test_vm_valid_virtualbox_api_version(loop, project, manager): with asyncio_patch("gns3server.compute.virtualbox.VirtualBox.execute", return_value=["API version: 4_3"]): vm = VirtualBoxVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, "test", False) - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) def test_vm_invalid_virtualbox_api_version(loop, project, manager): with asyncio_patch("gns3server.compute.virtualbox.VirtualBox.execute", return_value=["API version: 4_2"]): with pytest.raises(VirtualBoxError): vm = VirtualBoxVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, "test", False) - loop.run_until_complete(asyncio.async(vm.create())) + loop.run_until_complete(asyncio.ensure_future(vm.create())) def test_vm_adapter_add_nio_binding_adapter_not_exist(loop, vm, manager, free_console_port): nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"}) with pytest.raises(VirtualBoxError): - loop.run_until_complete(asyncio.async(vm.adapter_add_nio_binding(15, nio))) + loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(15, nio))) def test_json(vm, tmpdir, project): diff --git a/tests/compute/vmware/test_vmware_vm.py b/tests/compute/vmware/test_vmware_vm.py index 1b7747a7..fce5d58f 100644 --- a/tests/compute/vmware/test_vmware_vm.py +++ b/tests/compute/vmware/test_vmware_vm.py @@ -56,8 +56,8 @@ 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"}) vm.adapters = 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 @@ -66,8 +66,8 @@ 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"}) vm.adapters = 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 diff --git a/tests/compute/vpcs/test_vpcs_vm.py b/tests/compute/vpcs/test_vpcs_vm.py index 68e0a49e..f7862516 100644 --- a/tests/compute/vpcs/test_vpcs_vm.py +++ b/tests/compute/vpcs/test_vpcs_vm.py @@ -56,13 +56,13 @@ def test_vm(project, manager): def test_vm_check_vpcs_version(loop, vm, manager): with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.subprocess_check_output", return_value="Welcome to Virtual PC Simulator, version 0.9"): - loop.run_until_complete(asyncio.async(vm._check_vpcs_version())) + loop.run_until_complete(asyncio.ensure_future(vm._check_vpcs_version())) assert vm._vpcs_version == parse_version("0.9") def test_vm_check_vpcs_version_0_6_1(loop, vm, manager): with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.subprocess_check_output", return_value="Welcome to Virtual PC Simulator, version 0.6.1"): - loop.run_until_complete(asyncio.async(vm._check_vpcs_version())) + loop.run_until_complete(asyncio.ensure_future(vm._check_vpcs_version())) assert vm._vpcs_version == parse_version("0.6.1") @@ -71,7 +71,7 @@ def test_vm_invalid_vpcs_version(loop, manager, vm): with pytest.raises(VPCSError): nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}}) vm.port_add_nio_binding(0, nio) - loop.run_until_complete(asyncio.async(vm._check_vpcs_version())) + loop.run_until_complete(asyncio.ensure_future(vm._check_vpcs_version())) assert vm.name == "test" assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0f" @@ -81,7 +81,7 @@ def test_vm_invalid_vpcs_path(vm, manager, loop): with pytest.raises(VPCSError): 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" @@ -96,7 +96,7 @@ def test_start(loop, vm, async_run): 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: with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"): - loop.run_until_complete(asyncio.async(vm.start())) + loop.run_until_complete(asyncio.ensure_future(vm.start())) assert mock_exec.call_args[0] == (vm._vpcs_path(), '-p', str(vm._internal_console_port), @@ -169,7 +169,7 @@ 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 if sys.platform.startswith("win"): @@ -300,5 +300,5 @@ def test_close(vm, port_manager, loop): with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._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/conftest.py b/tests/conftest.py index 587c675d..da83b431 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -314,7 +314,7 @@ def async_run(loop): """ Shortcut for running in asyncio loop """ - return lambda x: loop.run_until_complete(asyncio.async(x)) + return lambda x: loop.run_until_complete(asyncio.ensure_future(x)) @pytest.yield_fixture diff --git a/tests/handlers/api/base.py b/tests/handlers/api/base.py index 91109c00..e71505ae 100644 --- a/tests/handlers/api/base.py +++ b/tests/handlers/api/base.py @@ -74,7 +74,7 @@ class Query: response = yield from self._session.ws_connect(self.get_url(path)) future.set_result(response) future = asyncio.Future() - asyncio.async(go_request(future)) + asyncio.ensure_future(go_request(future)) self._loop.run_until_complete(future) return future.result() @@ -85,7 +85,7 @@ class Query: - example if True the session is included inside documentation - raw do not JSON encode the query """ - return self._loop.run_until_complete(asyncio.async(self._async_fetch(method, path, body=body, **kwargs))) + return self._loop.run_until_complete(asyncio.ensure_future(self._async_fetch(method, path, body=body, **kwargs))) @asyncio.coroutine def _async_fetch(self, method, path, body=None, **kwargs): diff --git a/tests/handlers/api/controller/test_link.py b/tests/handlers/api/controller/test_link.py index 7a938d4f..e615281f 100644 --- a/tests/handlers/api/controller/test_link.py +++ b/tests/handlers/api/controller/test_link.py @@ -356,7 +356,7 @@ def test_pcap(http_controller, tmpdir, project, compute, loop): project._links = {link.id: link} future = asyncio.Future() - asyncio.async(go(future)) + asyncio.ensure_future(go(future)) response = loop.run_until_complete(future) assert response.status == 200 assert b'hello' == response.body diff --git a/tests/handlers/api/controller/test_project.py b/tests/handlers/api/controller/test_project.py index b0c852fa..ecb0c80b 100644 --- a/tests/handlers/api/controller/test_project.py +++ b/tests/handlers/api/controller/test_project.py @@ -179,7 +179,7 @@ def test_notification(http_controller, project, controller, loop, async_run): response.close() return response - response = async_run(asyncio.async(go())) + response = async_run(asyncio.ensure_future(go())) assert response.status == 200 assert b'"action": "ping"' in response.body assert b'"cpu_usage_percent"' in response.body diff --git a/tests/utils/test_asyncio.py b/tests/utils/test_asyncio.py index 0e4e3c48..942bf455 100644 --- a/tests/utils/test_asyncio.py +++ b/tests/utils/test_asyncio.py @@ -31,7 +31,7 @@ def test_wait_run_in_executor(loop): return param exec = wait_run_in_executor(change_var, "test") - result = loop.run_until_complete(asyncio.async(exec)) + result = loop.run_until_complete(asyncio.ensure_future(exec)) assert result == "test" @@ -42,7 +42,7 @@ def test_exception_wait_run_in_executor(loop): exec = wait_run_in_executor(raise_exception) with pytest.raises(Exception): - result = loop.run_until_complete(asyncio.async(exec)) + result = loop.run_until_complete(asyncio.ensure_future(exec)) @pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows") @@ -52,7 +52,7 @@ def test_subprocess_check_output(loop, tmpdir, restore_original_path): with open(path, "w+") as f: f.write("TEST") exec = subprocess_check_output("cat", path) - result = loop.run_until_complete(asyncio.async(exec)) + result = loop.run_until_complete(asyncio.ensure_future(exec)) assert result == "TEST" @@ -64,13 +64,13 @@ def test_wait_for_process_termination(loop): process = MagicMock() process.returncode = 0 exec = wait_for_process_termination(process) - loop.run_until_complete(asyncio.async(exec)) + loop.run_until_complete(asyncio.ensure_future(exec)) process = MagicMock() process.returncode = None exec = wait_for_process_termination(process, timeout=0.5) with pytest.raises(asyncio.TimeoutError): - loop.run_until_complete(asyncio.async(exec)) + loop.run_until_complete(asyncio.ensure_future(exec)) def test_lock_decorator(loop): From 3560cda06c13e67a3cb9a52b2228a5f4a114f7a1 Mon Sep 17 00:00:00 2001 From: grossmj Date: Fri, 24 Aug 2018 18:57:18 +0700 Subject: [PATCH 07/16] Use asyncio.ensure_future() instead of asyncio.async() with conservative approach to support Python < 3.4.4. Fixes https://github.com/GNS3/gns3-gui/issues/2566 --- gns3server/compute/base_manager.py | 3 ++- gns3server/compute/docker/docker_vm.py | 3 ++- gns3server/compute/dynamips/__init__.py | 5 ++-- gns3server/compute/dynamips/nodes/router.py | 4 +-- gns3server/compute/project.py | 4 +-- gns3server/compute/vmware/__init__.py | 3 ++- gns3server/controller/compute.py | 6 ++--- gns3server/controller/gns3vm/__init__.py | 4 +-- gns3server/controller/link.py | 4 ++- gns3server/controller/project.py | 3 ++- .../api/compute/notification_handler.py | 3 ++- .../api/controller/project_handler.py | 3 ++- .../handlers/api/controller/server_handler.py | 5 ++-- gns3server/utils/asyncio/__init__.py | 9 ++++++- .../utils/asyncio/raw_command_server.py | 10 +++++--- gns3server/utils/asyncio/telnet_server.py | 25 +++++++++++-------- gns3server/web/web_server.py | 7 +++--- 17 files changed, 63 insertions(+), 38 deletions(-) diff --git a/gns3server/compute/base_manager.py b/gns3server/compute/base_manager.py index f383a197..602b0017 100644 --- a/gns3server/compute/base_manager.py +++ b/gns3server/compute/base_manager.py @@ -30,6 +30,7 @@ log = logging.getLogger(__name__) from uuid import UUID, uuid4 from gns3server.utils.interfaces import is_interface_up +from gns3server.utils.asyncio import asyncio_ensure_future from ..config import Config from ..utils.asyncio import wait_run_in_executor from ..utils import force_unix_path @@ -127,7 +128,7 @@ class BaseManager: tasks = [] for node_id in self._nodes.keys(): - tasks.append(asyncio.async(self.close_node(node_id))) + tasks.append(asyncio_ensure_future(self.close_node(node_id))) if tasks: done, _ = yield from asyncio.wait(tasks) diff --git a/gns3server/compute/docker/docker_vm.py b/gns3server/compute/docker/docker_vm.py index 242078ee..8db488f8 100644 --- a/gns3server/compute/docker/docker_vm.py +++ b/gns3server/compute/docker/docker_vm.py @@ -29,6 +29,7 @@ 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 +from gns3server.utils.asyncio import asyncio_ensure_future from gns3server.utils.get_resource import get_resource from gns3server.ubridge.ubridge_error import UbridgeError, UbridgeNamespaceError @@ -567,7 +568,7 @@ class DockerVM(BaseNode): output_stream.feed_data(self.name.encode() + b" console is now available... Press RETURN to get started.\r\n") - asyncio.async(self._read_console_output(self._console_websocket, output_stream)) + asyncio_ensure_future(self._read_console_output(self._console_websocket, output_stream)) @asyncio.coroutine def _read_console_output(self, ws, out): diff --git a/gns3server/compute/dynamips/__init__.py b/gns3server/compute/dynamips/__init__.py index c972c86a..b06f5ca0 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 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 @@ -172,7 +173,7 @@ class Dynamips(BaseManager): tasks = [] for device in self._devices.values(): - tasks.append(asyncio.async(device.hypervisor.stop())) + tasks.append(asyncio_ensure_future(device.hypervisor.stop())) if tasks: done, _ = yield from asyncio.wait(tasks) @@ -196,7 +197,7 @@ class Dynamips(BaseManager): tasks = [] for device in self._devices.values(): if device.project.id == project.id: - tasks.append(asyncio.async(device.delete())) + tasks.append(asyncio_ensure_future(device.delete())) if tasks: done, _ = yield from asyncio.wait(tasks) diff --git a/gns3server/compute/dynamips/nodes/router.py b/gns3server/compute/dynamips/nodes/router.py index 8ff50afe..e42694d7 100644 --- a/gns3server/compute/dynamips/nodes/router.py +++ b/gns3server/compute/dynamips/nodes/router.py @@ -40,7 +40,7 @@ from ..nios.nio_udp import NIOUDP from gns3server.utils.file_watcher import FileWatcher -from gns3server.utils.asyncio import wait_run_in_executor, monitor_process +from gns3server.utils.asyncio import wait_run_in_executor, monitor_process, asyncio_ensure_future from gns3server.utils.images import md5sum @@ -196,7 +196,7 @@ class Router(BaseNode): """ Called when the NVRAM file has changed """ - asyncio.async(self.save_configs()) + asyncio_ensure_future(self.save_configs()) @property def dynamips_id(self): diff --git a/gns3server/compute/project.py b/gns3server/compute/project.py index 3792a8a7..ee2b1c19 100644 --- a/gns3server/compute/project.py +++ b/gns3server/compute/project.py @@ -29,7 +29,7 @@ from uuid import UUID, uuid4 from .port_manager import PortManager from .notification_manager import NotificationManager from ..config import Config -from ..utils.asyncio import wait_run_in_executor +from ..utils.asyncio import wait_run_in_executor, asyncio_ensure_future from ..utils.path import check_path_allowed, get_default_project_directory import logging @@ -346,7 +346,7 @@ class Project: tasks = [] for node in self._nodes: - tasks.append(asyncio.async(node.manager.close_node(node.id))) + tasks.append(asyncio_ensure_future(node.manager.close_node(node.id))) if tasks: done, _ = yield from asyncio.wait(tasks) diff --git a/gns3server/compute/vmware/__init__.py b/gns3server/compute/vmware/__init__.py index cda42c54..549a35ae 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__) @@ -738,4 +739,4 @@ if __name__ == '__main__': loop = asyncio.get_event_loop() vmware = VMware.instance() print("=> Check version") - loop.run_until_complete(asyncio.async(vmware.check_vmware_version())) + loop.run_until_complete(asyncio_ensure_future(vmware.check_vmware_version())) diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index da81b6e9..c3231a32 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -27,7 +27,7 @@ from operator import itemgetter from ..utils import parse_version from ..utils.images import list_images -from ..utils.asyncio import locked_coroutine +from ..utils.asyncio import locked_coroutine, asyncio_ensure_future from ..controller.controller_error import ControllerError from ..version import __version__, __version_info__ @@ -418,7 +418,7 @@ class Compute: if self._connection_failure == 5: log.warning("Cannot connect to compute '{}': {}".format(self._id, e)) yield from self._controller.close_compute_projects(self) - asyncio.get_event_loop().call_later(2, lambda: asyncio.async(self._try_reconnect())) + asyncio.get_event_loop().call_later(2, lambda: asyncio_ensure_future(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)) @@ -494,7 +494,7 @@ class Compute: # Try to reconnect after 1 seconds if server unavailable only if not during tests (otherwise we create a ressources usage bomb) if not hasattr(sys, "_called_from_test") or not sys._called_from_test: - asyncio.get_event_loop().call_later(1, lambda: asyncio.async(self.connect())) + asyncio.get_event_loop().call_later(1, lambda: asyncio_ensure_future(self.connect())) self._ws = None self._cpu_usage_percent = None self._memory_usage_percent = None diff --git a/gns3server/controller/gns3vm/__init__.py b/gns3server/controller/gns3vm/__init__.py index 7f5dcd76..8ffd25b6 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 +from ...utils.asyncio import locked_coroutine, asyncio_ensure_future from .vmware_gns3_vm import VMwareGNS3VM from .virtualbox_gns3_vm import VirtualBoxGNS3VM from .remote_gns3_vm import RemoteGNS3VM @@ -302,7 +302,7 @@ class GNS3VM: # check if the VM is in the same subnet as the local server, start 10 seconds later to give # some time for the compute in the VM to be ready for requests - asyncio.get_event_loop().call_later(10, lambda: asyncio.async(self._check_network(compute))) + asyncio.get_event_loop().call_later(10, lambda: asyncio_ensure_future(self._check_network(compute))) @asyncio.coroutine def _check_network(self, compute): diff --git a/gns3server/controller/link.py b/gns3server/controller/link.py index 9f7ac83a..822bdbae 100644 --- a/gns3server/controller/link.py +++ b/gns3server/controller/link.py @@ -22,6 +22,8 @@ import html import asyncio import aiohttp +from gns3server.utils.asyncio import asyncio_ensure_future + import logging log = logging.getLogger(__name__) @@ -296,7 +298,7 @@ class Link: self._capturing = True self._capture_file_name = capture_file_name - self._streaming_pcap = asyncio.async(self._start_streaming_pcap()) + self._streaming_pcap = asyncio_ensure_future(self._start_streaming_pcap()) self._project.controller.notification.emit("link.updated", self.__json__()) @asyncio.coroutine diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index 7d2ef53d..7c750f80 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -38,6 +38,7 @@ from ..utils.path import check_path_allowed, get_default_project_directory from ..utils.asyncio.pool import Pool from ..utils.asyncio import locked_coroutine 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 @@ -887,7 +888,7 @@ class Project: # Start all in the background without waiting for completion # we ignore errors because we want to let the user open # their project and fix it - asyncio.async(self.start_all()) + asyncio_ensure_future(self.start_all()) @asyncio.coroutine def wait_loaded(self): diff --git a/gns3server/handlers/api/compute/notification_handler.py b/gns3server/handlers/api/compute/notification_handler.py index 3580a286..d41bcaa9 100644 --- a/gns3server/handlers/api/compute/notification_handler.py +++ b/gns3server/handlers/api/compute/notification_handler.py @@ -20,6 +20,7 @@ import aiohttp from aiohttp.web import WebSocketResponse from gns3server.web.route import Route from gns3server.compute.notification_manager import NotificationManager +from gns3server.utils.asyncio import asyncio_ensure_future @asyncio.coroutine @@ -43,7 +44,7 @@ class NotificationHandler: ws = WebSocketResponse() yield from ws.prepare(request) - asyncio.async(process_websocket(ws)) + asyncio_ensure_future(process_websocket(ws)) with notifications.queue() as queue: while True: diff --git a/gns3server/handlers/api/controller/project_handler.py b/gns3server/handlers/api/controller/project_handler.py index e487c1d7..27ffbe2a 100644 --- a/gns3server/handlers/api/controller/project_handler.py +++ b/gns3server/handlers/api/controller/project_handler.py @@ -25,6 +25,7 @@ from gns3server.controller import Controller from gns3server.controller.import_project import import_project 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 ( @@ -246,7 +247,7 @@ class ProjectHandler: ws = aiohttp.web.WebSocketResponse() yield from ws.prepare(request) - asyncio.async(process_websocket(ws)) + asyncio_ensure_future(process_websocket(ws)) with controller.notification.queue(project) as queue: while True: diff --git a/gns3server/handlers/api/controller/server_handler.py b/gns3server/handlers/api/controller/server_handler.py index 972f8c54..465ea6ed 100644 --- a/gns3server/handlers/api/controller/server_handler.py +++ b/gns3server/handlers/api/controller/server_handler.py @@ -20,6 +20,7 @@ from gns3server.config import Config from gns3server.controller import Controller from gns3server.schemas.version import VERSION_SCHEMA from gns3server.version import __version__ +from gns3server.utils.asyncio import asyncio_ensure_future from aiohttp.web import HTTPConflict, HTTPForbidden @@ -57,7 +58,7 @@ class ServerHandler: tasks = [] for project in projects: - tasks.append(asyncio.async(project.close())) + tasks.append(asyncio_ensure_future(project.close())) if tasks: done, _ = yield from asyncio.wait(tasks) @@ -71,7 +72,7 @@ class ServerHandler: # then shutdown the server itself from gns3server.web.web_server import WebServer server = WebServer.instance() - asyncio.async(server.shutdown_server()) + asyncio_ensure_future(server.shutdown_server()) response.set_status(201) @Route.get( diff --git a/gns3server/utils/asyncio/__init__.py b/gns3server/utils/asyncio/__init__.py index 34e7571c..70a2cae1 100644 --- a/gns3server/utils/asyncio/__init__.py +++ b/gns3server/utils/asyncio/__init__.py @@ -108,7 +108,7 @@ def _check_process(process, termination_callback): def monitor_process(process, termination_callback): """Call termination_callback when a process dies""" - asyncio.async(_check_process(process, termination_callback)) + asyncio_ensure_future(_check_process(process, termination_callback)) @asyncio.coroutine @@ -158,3 +158,10 @@ def locked_coroutine(f): return (yield from f(*args, **kwargs)) return new_function + +#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 +except ImportError: + asyncio_ensure_future = getattr(asyncio, 'async') diff --git a/gns3server/utils/asyncio/raw_command_server.py b/gns3server/utils/asyncio/raw_command_server.py index da6e82c1..1a50ed0b 100644 --- a/gns3server/utils/asyncio/raw_command_server.py +++ b/gns3server/utils/asyncio/raw_command_server.py @@ -20,6 +20,8 @@ import copy import asyncio import asyncio.subprocess +from gns3server.utils.asyncio import asyncio_ensure_future + import logging log = logging.getLogger(__name__) @@ -69,8 +71,8 @@ class AsyncioRawCommandServer: else: replaces.append((replace[0], replace[1], )) - network_read = asyncio.async(network_reader.read(READ_SIZE)) - reader_read = asyncio.async(process_reader.read(READ_SIZE)) + network_read = asyncio_ensure_future(network_reader.read(READ_SIZE)) + reader_read = asyncio_ensure_future(process_reader.read(READ_SIZE)) timeout = 30 while True: @@ -89,7 +91,7 @@ class AsyncioRawCommandServer: if network_reader.at_eof(): raise ConnectionResetError() - network_read = asyncio.async(network_reader.read(READ_SIZE)) + network_read = asyncio_ensure_future(network_reader.read(READ_SIZE)) process_writer.write(data) yield from process_writer.drain() @@ -97,7 +99,7 @@ class AsyncioRawCommandServer: if process_reader.at_eof(): raise ConnectionResetError() - reader_read = asyncio.async(process_reader.read(READ_SIZE)) + reader_read = asyncio_ensure_future(process_reader.read(READ_SIZE)) for replace in replaces: data = data.replace(replace[0], replace[1]) diff --git a/gns3server/utils/asyncio/telnet_server.py b/gns3server/utils/asyncio/telnet_server.py index 782b12ae..2e736410 100644 --- a/gns3server/utils/asyncio/telnet_server.py +++ b/gns3server/utils/asyncio/telnet_server.py @@ -20,6 +20,8 @@ import asyncio import asyncio.subprocess import struct +from gns3server.utils.asyncio import asyncio_ensure_future + import logging log = logging.getLogger(__name__) @@ -212,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 @@ -229,13 +234,13 @@ class AsyncioTelnetServer: self._reader_process = network_reader if self._reader: if self._reader_process == network_reader: - self._current_read = asyncio.async(self._reader.read(READ_SIZE)) + self._current_read = asyncio_ensure_future(self._reader.read(READ_SIZE)) return self._current_read return None @asyncio.coroutine def _process(self, network_reader, network_writer, connection): - network_read = asyncio.async(network_reader.read(READ_SIZE)) + network_read = asyncio_ensure_future(network_reader.read(READ_SIZE)) reader_read = yield from self._get_reader(network_reader) while True: @@ -261,7 +266,7 @@ class AsyncioTelnetServer: if network_reader.at_eof(): raise ConnectionResetError() - network_read = asyncio.async(network_reader.read(READ_SIZE)) + network_read = asyncio_ensure_future(network_reader.read(READ_SIZE)) if IAC in data: data = yield from self._IAC_parser(data, network_reader, network_writer, connection) @@ -418,10 +423,10 @@ if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) loop = asyncio.get_event_loop() - process = loop.run_until_complete(asyncio.async(asyncio.subprocess.create_subprocess_exec("/bin/sh", "-i", - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.STDOUT, - stdin=asyncio.subprocess.PIPE))) + 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))) 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 c398e631..aad691d4 100644 --- a/gns3server/web/web_server.py +++ b/gns3server/web/web_server.py @@ -35,6 +35,7 @@ from ..compute import MODULES from ..compute.port_manager import PortManager from ..compute.qemu import Qemu from ..controller import Controller +from ..utils.asyncio import asyncio_ensure_future # do not delete this import import gns3server.handlers @@ -136,7 +137,7 @@ class WebServer: def signal_handler(signame, *args): log.warning("Server has got signal {}, exiting...".format(signame)) - asyncio.async(self.shutdown_server()) + asyncio_ensure_future(self.shutdown_server()) signals = ["SIGTERM", "SIGINT"] if sys.platform.startswith("win"): @@ -203,7 +204,7 @@ class WebServer: # Because with a large image collection # without md5sum already computed we start the # computing with server start - asyncio.async(Qemu.instance().list_images()) + asyncio_ensure_future(Qemu.instance().list_images()) def run(self): """ @@ -283,7 +284,7 @@ class WebServer: self._exit_handling() if server_config.getboolean("shell"): - asyncio.async(self.start_shell()) + asyncio_ensure_future(self.start_shell()) try: self._loop.run_forever() From ad9b6f42bf0515b066d699f15f759d103b62ad2e Mon Sep 17 00:00:00 2001 From: grossmj Date: Fri, 24 Aug 2018 18:59:10 +0700 Subject: [PATCH 08/16] Test with Python 3.7 on Travis. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) 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 From 902de3dd477d72a5e614212eccdb08a9af4ae7ce Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 25 Aug 2018 14:10:47 +0700 Subject: [PATCH 09/16] Refactor asyncio locking system for Python 3.7 support. Ref https://github.com/GNS3/gns3-gui/issues/2566 Ref https://github.com/GNS3/gns3-gui/issues/2568 --- gns3server/compute/base_node.py | 5 ++- gns3server/compute/docker/__init__.py | 5 ++- gns3server/compute/iou/iou_vm.py | 5 ++- .../compute/virtualbox/virtualbox_vm.py | 5 ++- gns3server/compute/vmware/vmware_vm.py | 5 ++- gns3server/controller/compute.py | 5 ++- gns3server/controller/gns3vm/__init__.py | 11 ++++-- gns3server/controller/project.py | 8 ++-- gns3server/ubridge/ubridge_hypervisor.py | 5 ++- gns3server/utils/asyncio/__init__.py | 38 ++++++++++--------- tests/conftest.py | 2 +- tests/utils/test_asyncio.py | 5 ++- 12 files changed, 57 insertions(+), 42 deletions(-) diff --git a/gns3server/compute/base_node.py b/gns3server/compute/base_node.py index ec1d8021..82e4eb6a 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 @@ -516,7 +516,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 e746f30e..f7ee075e 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 @@ -182,7 +182,8 @@ class Docker(BaseManager): autoping=True) return connection - @locked_coroutine + @locking + @asyncio.coroutine def pull_image(self, image, progress_callback=None): """ Pull image from docker repository diff --git a/gns3server/compute/iou/iou_vm.py b/gns3server/compute/iou/iou_vm.py index 0f2cb636..852a05f3 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 @@ -550,7 +550,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 2f878ffe..caefb0c9 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/vmware_vm.py b/gns3server/compute/vmware/vmware_vm.py index e048d1c8..15fac4f5 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 c3231a32..ff565a13 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -27,7 +27,7 @@ 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__, __version_info__ @@ -400,7 +400,8 @@ class Compute: except aiohttp.web.HTTPConflict: pass - @locked_coroutine + @locking + @asyncio.coroutine def connect(self): """ Check if remote server is accessible diff --git a/gns3server/controller/gns3vm/__init__.py b/gns3server/controller/gns3vm/__init__.py index 8ffd25b6..cf38a0f3 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 .remote_gns3_vm import RemoteGNS3VM @@ -265,7 +265,8 @@ class GNS3VM: except GNS3VMError as e: log.warn(str(e)) - @locked_coroutine + @locking + @asyncio.coroutine def start(self): """ Start the GNS3 VM @@ -339,7 +340,8 @@ class GNS3VM: 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 @@ -351,7 +353,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/project.py b/gns3server/controller/project.py index 7c750f80..b067806f 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -36,7 +36,7 @@ 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 +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 @@ -525,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. @@ -783,7 +784,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/ubridge/ubridge_hypervisor.py b/gns3server/ubridge/ubridge_hypervisor.py index 221ef207..092189ee 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 70a2cae1..adc2f2a6 100644 --- a/gns3server/utils/asyncio/__init__.py +++ b/gns3server/utils/asyncio/__init__.py @@ -138,26 +138,28 @@ 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 warranty - that this specific method of this class instance will not we - 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()) - - with (yield from getattr(args[0], lock_var_name)): - return (yield from f(*args, **kwargs)) - - return new_function + @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 #FIXME: conservative approach to supported versions, please remove it when we drop the support to Python < 3.4.4 try: 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/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) From f5dc635baabaccdde8a2961fbc87633bce66e6a2 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 25 Aug 2018 15:50:08 +0700 Subject: [PATCH 10/16] Fix test to support Python 3.7 Ref https://github.com/GNS3/gns3-gui/issues/2566 --- .../api/controller/project_handler.py | 26 ++++++++++++++----- tests/compute/qemu/test_qemu_vm.py | 6 ++--- tests/compute/traceng/test_traceng_vm.py | 10 +++---- tests/compute/vpcs/test_vpcs_vm.py | 10 +++---- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/gns3server/handlers/api/controller/project_handler.py b/gns3server/handlers/api/controller/project_handler.py index 27ffbe2a..46e17661 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 @@ -333,14 +334,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/tests/compute/qemu/test_qemu_vm.py b/tests/compute/qemu/test_qemu_vm.py index 90347176..07dbed25 100644 --- a/tests/compute/qemu/test_qemu_vm.py +++ b/tests/compute/qemu/test_qemu_vm.py @@ -150,9 +150,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 @@ -170,7 +170,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/traceng/test_traceng_vm.py b/tests/compute/traceng/test_traceng_vm.py index 974555fe..2f2133ef 100644 --- a/tests/compute/traceng/test_traceng_vm.py +++ b/tests/compute/traceng/test_traceng_vm.py @@ -66,7 +66,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 vm.ip_address = "192.168.1.1" with patch("sys.platform", return_value="win"): @@ -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 @@ -120,10 +120,10 @@ def test_stop(loop, vm, async_run): 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/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 From 814526ba2608af207b2d45fc9c2ac290872a71db Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 25 Aug 2018 16:00:40 +0700 Subject: [PATCH 11/16] Add missing coroutine decorator Ref https://github.com/GNS3/gns3-gui/issues/2566 --- gns3server/utils/asyncio/telnet_server.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gns3server/utils/asyncio/telnet_server.py b/gns3server/utils/asyncio/telnet_server.py index 2e736410..604ab914 100644 --- a/gns3server/utils/asyncio/telnet_server.py +++ b/gns3server/utils/asyncio/telnet_server.py @@ -322,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. From 38b72079b25112e637ac3bfa77c2133506882247 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 25 Aug 2018 18:10:40 +0700 Subject: [PATCH 12/16] Change file timestamps if necessary because ZIP does not support timestamps before 1980. Fixes #1360. --- gns3server/controller/export_project.py | 21 +++++++++++++++++++ gns3server/controller/snapshot.py | 2 +- .../api/controller/project_handler.py | 4 ++-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/gns3server/controller/export_project.py b/gns3server/controller/export_project.py index df727574..b8cd5a0c 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/snapshot.py b/gns3server/controller/snapshot.py index 70c3d173..cbae0429 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/handlers/api/controller/project_handler.py b/gns3server/handlers/api/controller/project_handler.py index 46e17661..37137ca2 100644 --- a/gns3server/handlers/api/controller/project_handler.py +++ b/gns3server/handlers/api/controller/project_handler.py @@ -304,8 +304,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", From 4d57a3befa5d1a67ace88335dd7b45c268563e20 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sun, 26 Aug 2018 02:43:40 -0700 Subject: [PATCH 13/16] Check if the VirtualBox host-only network exists when starting a GNS3 VM running on VirtualBox. Ref https://github.com/GNS3/gns3-vm/issues/102 --- .../controller/gns3vm/virtualbox_gns3_vm.py | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py index f491e32f..9c282a74 100644 --- a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py +++ b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py @@ -107,7 +107,6 @@ class VirtualBoxGNS3VM(BaseGNS3VM): Check if the DHCP server associated with a vboxnet is enabled. :param vboxnet: vboxnet name - :returns: boolean """ @@ -125,6 +124,25 @@ 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 _check_vbox_port_forwarding(self): """ @@ -158,18 +176,23 @@ 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('The 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('The 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)): + 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)) From 8d4e73d23ce54f0ec35210c44c239795514e0e48 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sun, 26 Aug 2018 03:28:38 -0700 Subject: [PATCH 14/16] Replace vboxnet0 (if it does not exist) by the first available vboxnet interface on Windows. Fixes https://github.com/GNS3/gns3-vm/issues/102 --- .../controller/gns3vm/virtualbox_gns3_vm.py | 50 +++++++++++++++++-- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py index 9c282a74..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 @@ -143,6 +144,22 @@ class VirtualBoxGNS3VM(BaseGNS3VM): 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): """ @@ -176,20 +193,29 @@ 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 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 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('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)): - 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 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 "{}"'.format(vboxnet)) @@ -334,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)) From 00cf66fb0f7db6be39b59ca3f7361b472e660f4a Mon Sep 17 00:00:00 2001 From: grossmj Date: Tue, 28 Aug 2018 15:42:06 +0700 Subject: [PATCH 15/16] Report GNS3 VM errors to the GUI server summary. Ref #1359. --- gns3server/controller/compute.py | 8 ++++++++ gns3server/controller/gns3vm/__init__.py | 15 +++++++++------ gns3server/web/web_server.py | 10 ++++++++-- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index ff565a13..fe981241 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -138,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): """ diff --git a/gns3server/controller/gns3vm/__init__.py b/gns3server/controller/gns3vm/__init__.py index cf38a0f3..a5fcee4b 100644 --- a/gns3server/controller/gns3vm/__init__.py +++ b/gns3server/controller/gns3vm/__init__.py @@ -246,13 +246,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): @@ -290,8 +292,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), diff --git a/gns3server/web/web_server.py b/gns3server/web/web_server.py index aad691d4..25427af4 100644 --- a/gns3server/web/web_server.py +++ b/gns3server/web/web_server.py @@ -137,7 +137,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"): @@ -295,4 +298,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 From b7dd8b517665f6b450b3f706ee0fa1ae5b190427 Mon Sep 17 00:00:00 2001 From: grossmj Date: Tue, 28 Aug 2018 17:10:24 +0700 Subject: [PATCH 16/16] Catch asyncio.CancelledError when shutting down the server. --- gns3server/handlers/api/controller/server_handler.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gns3server/handlers/api/controller/server_handler.py b/gns3server/handlers/api/controller/server_handler.py index 465ea6ed..fcc7238a 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(