Merge branch '2.1' into 2.2

# Conflicts:
#	gns3server/compute/docker/docker_vm.py
#	gns3server/controller/compute.py
#	gns3server/controller/gns3vm/__init__.py
#	gns3server/controller/link.py
#	gns3server/controller/project.py
#	gns3server/handlers/api/controller/project_handler.py
#	gns3server/handlers/api/controller/server_handler.py
#	gns3server/utils/asyncio/__init__.py
#	gns3server/utils/asyncio/telnet_server.py
#	gns3server/version.py
#	gns3server/web/web_server.py
#	tests/compute/qemu/test_qemu_vm.py
This commit is contained in:
grossmj 2018-08-29 15:57:54 +07:00
commit 33e8710495
43 changed files with 362 additions and 193 deletions

View File

@ -30,3 +30,4 @@ env:
- PYTHON_VERSION=3.4 - PYTHON_VERSION=3.4
- PYTHON_VERSION=3.5 - PYTHON_VERSION=3.5
- PYTHON_VERSION=3.6 - PYTHON_VERSION=3.6
- PYTHON_VERSION=3.7

View File

@ -1,5 +1,13 @@
# Change Log # 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 ## 2.1.8 14/06/2018
* 'caplog.text()' syntax is deprecated, use 'caplog.text' property instead. * 'caplog.text()' syntax is deprecated, use 'caplog.text' property instead.

View File

@ -29,7 +29,7 @@ import re
from gns3server.utils.interfaces import interfaces from gns3server.utils.interfaces import interfaces
from ..compute.port_manager import PortManager 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 ..utils.asyncio.telnet_server import AsyncioTelnetServer
from ..ubridge.hypervisor import Hypervisor from ..ubridge.hypervisor import Hypervisor
from ..ubridge.ubridge_error import UbridgeError from ..ubridge.ubridge_error import UbridgeError
@ -547,7 +547,8 @@ class BaseNode:
except UbridgeError as e: except UbridgeError as e:
raise UbridgeError("Error while sending command '{}': {}: {}".format(command, e, self._ubridge_hypervisor.read_stdout())) raise UbridgeError("Error while sending command '{}': {}: {}".format(command, e, self._ubridge_hypervisor.read_stdout()))
@locked_coroutine @locking
@asyncio.coroutine
def _start_ubridge(self): def _start_ubridge(self):
""" """
Starts uBridge (handles connections to and from this node). Starts uBridge (handles connections to and from this node).

View File

@ -25,7 +25,7 @@ import asyncio
import logging import logging
import aiohttp import aiohttp
from gns3server.utils import parse_version 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.base_manager import BaseManager
from gns3server.compute.docker.docker_vm import DockerVM from gns3server.compute.docker.docker_vm import DockerVM
from gns3server.compute.docker.docker_error import DockerError, DockerHttp304Error, DockerHttp404Error from gns3server.compute.docker.docker_error import DockerError, DockerHttp304Error, DockerHttp404Error
@ -187,7 +187,8 @@ class Docker(BaseManager):
autoping=True) autoping=True)
return connection return connection
@locked_coroutine @locking
@asyncio.coroutine
def pull_image(self, image, progress_callback=None): def pull_image(self, image, progress_callback=None):
""" """
Pulls an image from the Docker repository Pulls an image from the Docker repository

View File

@ -28,7 +28,8 @@ import os
from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer
from gns3server.utils.asyncio.raw_command_server import AsyncioRawCommandServer from gns3server.utils.asyncio.raw_command_server import AsyncioRawCommandServer
from gns3server.utils.asyncio import wait_for_file_creation, asyncio_ensure_future from gns3server.utils.asyncio import wait_for_file_creation
from gns3server.utils.asyncio import asyncio_ensure_future
from gns3server.utils.get_resource import get_resource from gns3server.utils.get_resource import get_resource
from gns3server.ubridge.ubridge_error import UbridgeError, UbridgeNamespaceError from gns3server.ubridge.ubridge_error import UbridgeError, UbridgeNamespaceError

View File

@ -36,6 +36,7 @@ log = logging.getLogger(__name__)
from gns3server.utils.interfaces import interfaces, is_interface_up from gns3server.utils.interfaces import interfaces, is_interface_up
from gns3server.utils.asyncio import wait_run_in_executor, asyncio_ensure_future from gns3server.utils.asyncio import wait_run_in_executor, asyncio_ensure_future
from gns3server.utils import parse_version from gns3server.utils import parse_version
from gns3server.utils.asyncio import asyncio_ensure_future
from uuid import uuid4 from uuid import uuid4
from ..base_manager import BaseManager from ..base_manager import BaseManager
from ..port_manager import PortManager from ..port_manager import PortManager

View File

@ -43,7 +43,7 @@ from .utils.iou_export import nvram_export
from gns3server.ubridge.ubridge_error import UbridgeError from gns3server.ubridge.ubridge_error import UbridgeError
from gns3server.utils.file_watcher import FileWatcher from gns3server.utils.file_watcher import FileWatcher
from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer 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.asyncio
import gns3server.utils.images import gns3server.utils.images
@ -552,7 +552,8 @@ class IOUVM(BaseNode):
# configure networking support # configure networking support
yield from self._networking() yield from self._networking()
@locked_coroutine @locking
@asyncio.coroutine
def _networking(self): def _networking(self):
""" """
Configures the IOL bridge in uBridge. Configures the IOL bridge in uBridge.

View File

@ -33,7 +33,7 @@ import xml.etree.ElementTree as ET
from gns3server.utils import parse_version from gns3server.utils import parse_version
from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer
from gns3server.utils.asyncio.serial import asyncio_open_serial 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.virtualbox.virtualbox_error import VirtualBoxError
from gns3server.compute.nios.nio_udp import NIOUDP from gns3server.compute.nios.nio_udp import NIOUDP
from gns3server.compute.adapters.ethernet_adapter import EthernetAdapter from gns3server.compute.adapters.ethernet_adapter import EthernetAdapter
@ -296,7 +296,8 @@ class VirtualBoxVM(BaseNode):
if (yield from self.check_hw_virtualization()): if (yield from self.check_hw_virtualization()):
self._hw_virtualization = True self._hw_virtualization = True
@locked_coroutine @locking
@asyncio.coroutine
def stop(self): def stop(self):
""" """
Stops this VirtualBox VM. Stops this VirtualBox VM.

View File

@ -32,6 +32,7 @@ import shlex
from collections import OrderedDict from collections import OrderedDict
from gns3server.utils.interfaces import interfaces from gns3server.utils.interfaces import interfaces
from gns3server.utils.asyncio import subprocess_check_output from gns3server.utils.asyncio import subprocess_check_output
from gns3server.utils.asyncio import asyncio_ensure_future
from gns3server.utils import parse_version from gns3server.utils import parse_version
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -26,7 +26,7 @@ import tempfile
from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer
from gns3server.utils.asyncio.serial import asyncio_open_serial 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 collections import OrderedDict
from .vmware_error import VMwareError from .vmware_error import VMwareError
from ..nios.nio_udp import NIOUDP from ..nios.nio_udp import NIOUDP
@ -94,7 +94,8 @@ class VMwareVM(BaseNode):
return self._vmnets return self._vmnets
@locked_coroutine @locking
@asyncio.coroutine
def _control_vm(self, subcommand, *additional_args): def _control_vm(self, subcommand, *additional_args):
args = [self._vmx_path] args = [self._vmx_path]

View File

@ -27,9 +27,9 @@ from operator import itemgetter
from ..utils import parse_version from ..utils import parse_version
from ..utils.images import list_images 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 ..controller.controller_error import ControllerError
from ..version import __version__ from ..version import __version__, __version_info__
import logging import logging
@ -95,6 +95,7 @@ class Compute:
self._set_auth(user, password) self._set_auth(user, password)
self._cpu_usage_percent = None self._cpu_usage_percent = None
self._memory_usage_percent = None self._memory_usage_percent = None
self._last_error = None
self._capabilities = { self._capabilities = {
"version": None, "version": None,
"node_types": [] "node_types": []
@ -137,6 +138,14 @@ class Compute:
self._password = None self._password = None
self._auth = aiohttp.BasicAuth(self._user, "") 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 @asyncio.coroutine
def interfaces(self): def interfaces(self):
""" """
@ -301,7 +310,8 @@ class Compute:
"connected": self._connected, "connected": self._connected,
"cpu_usage_percent": self._cpu_usage_percent, "cpu_usage_percent": self._cpu_usage_percent,
"memory_usage_percent": self._memory_usage_percent, "memory_usage_percent": self._memory_usage_percent,
"capabilities": self._capabilities "capabilities": self._capabilities,
"last_error": self._last_error
} }
@asyncio.coroutine @asyncio.coroutine
@ -398,7 +408,8 @@ class Compute:
except aiohttp.web.HTTPConflict: except aiohttp.web.HTTPConflict:
pass pass
@locked_coroutine @locking
@asyncio.coroutine
def connect(self): def connect(self):
""" """
Check if remote server is accessible Check if remote server is accessible
@ -420,7 +431,7 @@ class Compute:
if self._connection_failure == 10: if self._connection_failure == 10:
log.error("Could not connect to compute '{}' after multiple attempts: {}".format(self._id, e)) log.error("Could not connect to compute '{}' after multiple attempts: {}".format(self._id, e))
yield from self._controller.close_compute_projects(self) yield from self._controller.close_compute_projects(self)
asyncio.get_event_loop().call_later(2, lambda: asyncio_ensure_future(self._try_reconnect())) asyncio.get_event_loop().call_later(2, lambda: asyncio.async(self._try_reconnect()))
return return
except aiohttp.web.HTTPNotFound: 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)) raise aiohttp.web.HTTPConflict(text="The server {} is not a GNS3 server or it's a 1.X server".format(self._id))
@ -432,16 +443,36 @@ class Compute:
raise aiohttp.web.HTTPConflict(text="Invalid server url for server {}".format(self._id)) raise aiohttp.web.HTTPConflict(text="Invalid server url for server {}".format(self._id))
if "version" not in response.json: if "version" not in response.json:
msg = "The server {} is not a GNS3 server".format(self._id)
log.error(msg)
self._http_session.close() 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 self._capabilities = response.json
if parse_version(__version__)[:2] != parse_version(response.json["version"])[:2]:
self._http_session.close() if response.json["version"].split("-")[0] != __version__.split("-")[0]:
raise aiohttp.web.HTTPConflict(text="The server {} versions are not compatible {} != {}".format(self._id, __version__, response.json["version"])) 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._notifications = asyncio.gather(self._connect_notification())
self._connected = True self._connected = True
self._connection_failure = 0 self._connection_failure = 0
self._last_error = None
self._controller.notification.controller_emit("compute.updated", self.__json__()) self._controller.notification.controller_emit("compute.updated", self.__json__())
@asyncio.coroutine @asyncio.coroutine

View File

@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import os import os
import sys
import json import json
import asyncio import asyncio
import aiohttp import aiohttp
@ -23,6 +24,7 @@ import zipfile
import tempfile import tempfile
import zipstream import zipstream
from datetime import datetime
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -77,6 +79,7 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id
# ignore the .gns3 file # ignore the .gns3 file
if file.endswith(".gns3"): if file.endswith(".gns3"):
continue continue
_patch_mtime(path)
zstream.write(path, os.path.relpath(path, project._path), compress_type=zipfile.ZIP_DEFLATED) zstream.write(path, os.path.relpath(path, project._path), compress_type=zipfile.ZIP_DEFLATED)
# Export files from remote computes # Export files from remote computes
@ -99,12 +102,29 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id
f.write(data) f.write(data)
response.close() response.close()
f.close() f.close()
_patch_mtime(temp_path)
zstream.write(temp_path, arcname=compute_file["path"], compress_type=zipfile.ZIP_DEFLATED) zstream.write(temp_path, arcname=compute_file["path"], compress_type=zipfile.ZIP_DEFLATED)
downloaded_files.add(compute_file['path']) downloaded_files.add(compute_file['path'])
return zstream 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): def _is_exportable(path):
""" """
:returns: True if file should not be included in the final archive :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): if os.path.exists(path):
arcname = os.path.join("images", directory, os.path.basename(image)) arcname = os.path.join("images", directory, os.path.basename(image))
_patch_mtime(path)
zstream.write(path, arcname) zstream.write(path, arcname)
return return

View File

@ -21,7 +21,7 @@ import asyncio
import aiohttp import aiohttp
import ipaddress 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 .vmware_gns3_vm import VMwareGNS3VM
from .virtualbox_gns3_vm import VirtualBoxGNS3VM from .virtualbox_gns3_vm import VirtualBoxGNS3VM
from .hyperv_gns3_vm import HyperVGNS3VM from .hyperv_gns3_vm import HyperVGNS3VM
@ -278,13 +278,15 @@ class GNS3VM:
except GNS3VMError as e: except GNS3VMError as e:
# User will receive the error later when they will try to use the node # User will receive the error later when they will try to use the node
try: try:
yield from self._controller.add_compute(compute_id="vm", compute = yield from self._controller.add_compute(compute_id="vm",
name="GNS3 VM ({})".format(self.current_engine().vmname), name="GNS3 VM ({})".format(self.current_engine().vmname),
host=None, host=None,
force=True) force=True)
compute.set_last_error(str(e))
except aiohttp.web.HTTPConflict: except aiohttp.web.HTTPConflict:
pass pass
log.error("Can't start the GNS3 VM: %s", str(e)) log.error("Cannot start the GNS3 VM: {}".format(e))
@asyncio.coroutine @asyncio.coroutine
def exit_vm(self): def exit_vm(self):
@ -298,7 +300,8 @@ class GNS3VM:
except GNS3VMError as e: except GNS3VMError as e:
log.warning(str(e)) log.warning(str(e))
@locked_coroutine @locking
@asyncio.coroutine
def start(self): def start(self):
""" """
Start the GNS3 VM Start the GNS3 VM
@ -323,8 +326,9 @@ class GNS3VM:
yield from engine.start() yield from engine.start()
except Exception as e: except Exception as e:
yield from self._controller.delete_compute("vm") 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)) yield from compute.update(name="GNS3 VM ({})".format(engine.vmname))
compute.set_last_error(str(e))
raise e raise e
yield from compute.connect() # we can connect now that the VM has started yield from compute.connect() # we can connect now that the VM has started
yield from compute.update(name="GNS3 VM ({})".format(engine.vmname), yield from compute.update(name="GNS3 VM ({})".format(engine.vmname),
@ -370,8 +374,11 @@ class GNS3VM:
self._controller.notification.controller_emit("log.warning", {"message": msg}) self._controller.notification.controller_emit("log.warning", {"message": msg})
except ComputeError as e: except ComputeError as e:
log.warning("Could not check the VM is in the same subnet as the local server: {}".format(e)) log.warning("Could not check the VM is in the same subnet as the local server: {}".format(e))
except aiohttp.web.HTTPConflict as e:
log.warning("Could not check the VM is in the same subnet as the local server: {}".format(e.text))
@locked_coroutine @locking
@asyncio.coroutine
def _suspend(self): def _suspend(self):
""" """
Suspend the GNS3 VM Suspend the GNS3 VM
@ -383,7 +390,8 @@ class GNS3VM:
log.info("Suspend the GNS3 VM") log.info("Suspend the GNS3 VM")
yield from engine.suspend() yield from engine.suspend()
@locked_coroutine @locking
@asyncio.coroutine
def _stop(self): def _stop(self):
""" """
Stop the GNS3 VM Stop the GNS3 VM

View File

@ -15,6 +15,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import aiohttp import aiohttp
import logging import logging
import asyncio import asyncio
@ -107,7 +108,6 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
Check if the DHCP server associated with a vboxnet is enabled. Check if the DHCP server associated with a vboxnet is enabled.
:param vboxnet: vboxnet name :param vboxnet: vboxnet name
:returns: boolean :returns: boolean
""" """
@ -125,6 +125,41 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
return True return True
return False return False
@asyncio.coroutine
def _check_vboxnet_exists(self, vboxnet):
"""
Check if the vboxnet interface exists
:param vboxnet: vboxnet name
:returns: boolean
"""
properties = yield from self._execute("list", ["hostonlyifs"])
for prop in properties.splitlines():
try:
name, value = prop.split(':', 1)
except ValueError:
continue
if name.strip() == "Name" and value.strip() == vboxnet:
return True
return False
@asyncio.coroutine
def _find_first_available_vboxnet(self):
"""
Find the first available vboxnet.
"""
properties = yield from self._execute("list", ["hostonlyifs"])
for prop in properties.splitlines():
try:
name, value = prop.split(':', 1)
except ValueError:
continue
if name.strip() == "Name":
return value.strip()
return None
@asyncio.coroutine @asyncio.coroutine
def _check_vbox_port_forwarding(self): def _check_vbox_port_forwarding(self):
""" """
@ -158,18 +193,32 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
# get a NAT interface number # get a NAT interface number
nat_interface_number = yield from self._look_for_interface("nat") nat_interface_number = yield from self._look_for_interface("nat")
if nat_interface_number < 0: if nat_interface_number < 0:
raise GNS3VMError("The GNS3 VM: {} must have a NAT interface configured in order to start".format(self.vmname)) raise GNS3VMError('VM "{}" must have a NAT interface configured in order to start'.format(self.vmname))
hostonly_interface_number = yield from self._look_for_interface("hostonly") hostonly_interface_number = yield from self._look_for_interface("hostonly")
if hostonly_interface_number < 0: if hostonly_interface_number < 0:
raise GNS3VMError("The GNS3 VM: {} must have a host only interface configured in order to start".format(self.vmname)) raise GNS3VMError('VM "{}" must have a host-only interface configured in order to start'.format(self.vmname))
vboxnet = yield from self._look_for_vboxnet(hostonly_interface_number) vboxnet = yield from self._look_for_vboxnet(hostonly_interface_number)
if vboxnet is None: if vboxnet is None:
raise GNS3VMError("VirtualBox host-only network could not be found for interface {} on GNS3 VM".format(hostonly_interface_number)) raise GNS3VMError('A VirtualBox host-only network could not be found on network adapter {} for "{}"'.format(hostonly_interface_number, self._vmname))
if not (yield from self._check_vboxnet_exists(vboxnet)):
if sys.platform.startswith("win") and vboxnet == "vboxnet0":
# The GNS3 VM is configured with vboxnet0 by default which is not available
# on Windows. Try to patch this with the first available vboxnet we find.
first_available_vboxnet = yield from self._find_first_available_vboxnet()
if first_available_vboxnet is None:
raise GNS3VMError('Please add a VirtualBox host-only network with DHCP enabled and attached it to network adapter {} for "{}"'.format(hostonly_interface_number, self._vmname))
yield from self.set_hostonly_network(hostonly_interface_number, first_available_vboxnet)
vboxnet = first_available_vboxnet
else:
raise GNS3VMError('VirtualBox host-only network "{}" does not exist, please make the sure the network adapter {} configuration is valid for "{}"'.format(vboxnet,
hostonly_interface_number,
self._vmname))
if not (yield from self._check_dhcp_server(vboxnet)): 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() vm_state = yield from self._get_state()
log.info('"{}" state is {}'.format(self._vmname, vm_state)) log.info('"{}" state is {}'.format(self._vmname, vm_state))
@ -311,3 +360,17 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
yield from self._execute("modifyvm", [self._vmname, "--memory", str(ram)], timeout=3) yield from self._execute("modifyvm", [self._vmname, "--memory", str(ram)], timeout=3)
log.info("GNS3 VM RAM amount set to {}".format(ram)) 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))

View File

@ -33,8 +33,8 @@ class ATMPort(SerialPort):
""" """
return "ATM" return "ATM"
@property @staticmethod
def short_name_type(self): def short_name_type():
""" """
Returns the short name type for this port. Returns the short name type for this port.
@ -42,10 +42,6 @@ class ATMPort(SerialPort):
""" """
return "a" return "a"
@property
def short_name(self):
return "{}".format(self._port_number)
@property @property
def data_link_types(self): def data_link_types(self):
""" """

View File

@ -39,8 +39,8 @@ class EthernetPort(Port):
return "Ethernet" return "Ethernet"
@property @staticmethod
def short_name_type(self): def short_name_type():
""" """
Returns the short name type for this port. Returns the short name type for this port.

View File

@ -34,8 +34,8 @@ class FastEthernetPort(Port):
return "FastEthernet" return "FastEthernet"
@property @staticmethod
def short_name_type(self): def short_name_type():
""" """
Returns the short name type for this port. Returns the short name type for this port.

View File

@ -34,10 +34,6 @@ class FrameRelayPort(SerialPort):
return "FrameRelay" return "FrameRelay"
@property
def short_name(self):
return "{}".format(self._port_number)
@property @property
def data_link_types(self): def data_link_types(self):
""" """

View File

@ -34,8 +34,8 @@ class GigabitEthernetPort(Port):
return "GigabitEthernet" return "GigabitEthernet"
@property @staticmethod
def short_name_type(self): def short_name_type():
""" """
Returns the short name type for this port. Returns the short name type for this port.

View File

@ -85,9 +85,9 @@ class Port:
if self._short_name: if self._short_name:
return self._short_name return self._short_name
elif '/' in self._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)): 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 return self._name
@short_name.setter @short_name.setter

View File

@ -209,7 +209,7 @@ class DynamipsPortFactory:
for port_number in range(0, cls.ADAPTER_MATRIX[properties[name]]["nb_ports"]): for port_number in range(0, cls.ADAPTER_MATRIX[properties[name]]["nb_ports"]):
name = "{}{}/{}".format(port_class.long_name_type(), adapter_number, port_number) name = "{}{}/{}".format(port_class.long_name_type(), adapter_number, port_number)
port = port_class(name, adapter_number, 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) ports.append(port)
adapter_number += 1 adapter_number += 1
elif name.startswith("wic") and properties[name]: elif name.startswith("wic") and properties[name]:
@ -218,7 +218,7 @@ class DynamipsPortFactory:
for port_number in range(0, cls.WIC_MATRIX[properties[name]]["nb_ports"]): 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) name = "{}{}/{}".format(port_class.long_name_type(), 0, display_wic_port_number)
port = port_class(name, 0, 0, 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) ports.append(port)
display_wic_port_number += 1 display_wic_port_number += 1
wic_port_number += 1 wic_port_number += 1

View File

@ -33,8 +33,8 @@ class POSPort(SerialPort):
""" """
return "POS" return "POS"
@property @staticmethod
def short_name_type(self): def short_name_type():
""" """
Returns the short name type for this port. Returns the short name type for this port.

View File

@ -34,8 +34,8 @@ class SerialPort(Port):
return "Serial" return "Serial"
@property @staticmethod
def short_name_type(self): def short_name_type():
""" """
Returns the short name type for this port. Returns the short name type for this port.

View File

@ -36,8 +36,9 @@ from .udp_link import UDPLink
from ..config import Config from ..config import Config
from ..utils.path import check_path_allowed, get_default_project_directory from ..utils.path import check_path_allowed, get_default_project_directory
from ..utils.asyncio.pool import Pool from ..utils.asyncio.pool import Pool
from ..utils.asyncio import locked_coroutine, asyncio_ensure_future from ..utils.asyncio import locking
from ..utils.asyncio import wait_run_in_executor from ..utils.asyncio import wait_run_in_executor
from ..utils.asyncio import asyncio_ensure_future
from .export_project import export_project from .export_project import export_project
from .import_project import import_project from .import_project import import_project
@ -524,7 +525,8 @@ class Project:
self.dump() self.dump()
return node return node
@locked_coroutine @locking
@asyncio.coroutine
def __delete_node_links(self, node): def __delete_node_links(self, node):
""" """
Delete all link connected to this node. Delete all link connected to this node.
@ -814,7 +816,8 @@ class Project:
def _topology_file(self): def _topology_file(self):
return os.path.join(self.path, self._filename) return os.path.join(self.path, self._filename)
@locked_coroutine @locking
@asyncio.coroutine
def open(self): def open(self):
""" """
Load topology elements Load topology elements

View File

@ -101,7 +101,7 @@ class Snapshot:
with tempfile.TemporaryDirectory() as tmpdir: with tempfile.TemporaryDirectory() as tmpdir:
zipstream = yield from export_project(self._project, tmpdir, keep_compute_id=True, allow_all_nodes=True) 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) 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)) raise aiohttp.web.HTTPConflict(text="Could not create snapshot file '{}': {}".format(self.path, e))
@asyncio.coroutine @asyncio.coroutine

View File

@ -57,7 +57,7 @@ class CrashReport:
Report crash to a third party service 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"): if hasattr(sys, "frozen"):
cacert = get_resource("cacert.pem") cacert = get_resource("cacert.pem")
if cacert is not None and os.path.isfile(cacert): if cacert is not None and os.path.isfile(cacert):

View File

@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import os import os
import sys
import aiohttp import aiohttp
import asyncio import asyncio
import tempfile import tempfile
@ -27,6 +28,7 @@ from gns3server.controller.export_project import export_project
from gns3server.config import Config from gns3server.config import Config
from gns3server.utils.asyncio import asyncio_ensure_future from gns3server.utils.asyncio import asyncio_ensure_future
from gns3server.schemas.project import ( from gns3server.schemas.project import (
PROJECT_OBJECT_SCHEMA, PROJECT_OBJECT_SCHEMA,
PROJECT_UPDATE_SCHEMA, PROJECT_UPDATE_SCHEMA,
@ -317,8 +319,8 @@ class ProjectHandler:
yield from response.write_eof() yield from response.write_eof()
# Will be raise if you have no space left or permission issue on your temporary directory # Will be raise if you have no space left or permission issue on your temporary directory
# RuntimeError: something was wrong during the zip process # RuntimeError: something was wrong during the zip process
except (OSError, RuntimeError) as e: except (ValueError, OSError, RuntimeError) as e:
raise aiohttp.web.HTTPNotFound(text="Can't export project: {}".format(str(e))) raise aiohttp.web.HTTPNotFound(text="Cannot export project: {}".format(str(e)))
@Route.post( @Route.post(
r"/projects/{project_id}/import", r"/projects/{project_id}/import",
@ -347,14 +349,25 @@ class ProjectHandler:
# We write the content to a temporary location and after we extract it all. # 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. # 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 # 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: try:
with tempfile.SpooledTemporaryFile(max_size=10000) as temp: if sys.version_info >= (3, 7) and sys.version_info < (3, 8):
while True: with tempfile.TemporaryFile() as temp:
chunk = yield from request.content.read(1024) while True:
if not chunk: chunk = yield from request.content.read(1024)
break if not chunk:
temp.write(chunk) break
project = yield from import_project(controller, request.match_info["project_id"], temp, location=path, name=name) 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: except OSError as e:
raise aiohttp.web.HTTPInternalServerError(text="Could not import the project: {}".format(e)) raise aiohttp.web.HTTPInternalServerError(text="Could not import the project: {}".format(e))

View File

@ -72,7 +72,10 @@ class ServerHandler:
# then shutdown the server itself # then shutdown the server itself
from gns3server.web.web_server import WebServer from gns3server.web.web_server import WebServer
server = WebServer.instance() server = WebServer.instance()
asyncio_ensure_future(server.shutdown_server()) try:
asyncio_ensure_future(server.shutdown_server())
except asyncio.CancelledError:
pass
response.set_status(201) response.set_status(201)
@Route.get( @Route.get(
@ -127,6 +130,7 @@ class ServerHandler:
return return
try: try:
controller.settings = request.json controller.settings = request.json
#controller.save()
except (OSError, PermissionError) as e: except (OSError, PermissionError) as e:
raise HTTPConflict(text="Can't save the settings {}".format(str(e))) raise HTTPConflict(text="Can't save the settings {}".format(str(e)))
response.json(controller.settings) response.json(controller.settings)

View File

@ -104,6 +104,10 @@ COMPUTE_OBJECT_SCHEMA = {
"maximum": 100, "maximum": 100,
"minimum": 0 "minimum": 0
}, },
"last_error": {
"description": "Last error on the compute",
"type": ["string", "null"]
},
"capabilities": CAPABILITIES_SCHEMA "capabilities": CAPABILITIES_SCHEMA
}, },
"additionalProperties": False, "additionalProperties": False,

View File

@ -133,7 +133,7 @@ QEMU_CREATE_SCHEMA = {
}, },
"boot_priority": { "boot_priority": {
"description": "QEMU boot priority", "description": "QEMU boot priority",
"enum": ["c", "d", "n", "cn", "cd"] "enum": ["c", "d", "n", "cn", "cd", "dn", "dc", "nc", "nd"]
}, },
"ram": { "ram": {
"description": "Amount of RAM in MB", "description": "Amount of RAM in MB",
@ -319,7 +319,7 @@ QEMU_UPDATE_SCHEMA = {
}, },
"boot_priority": { "boot_priority": {
"description": "QEMU boot priority", "description": "QEMU boot priority",
"enum": ["c", "d", "n", "cn", "cd"] "enum": ["c", "d", "n", "cn", "cd", "dn", "dc", "nc", "nd"]
}, },
"ram": { "ram": {
"description": "Amount of RAM in MB", "description": "Amount of RAM in MB",
@ -504,7 +504,7 @@ QEMU_OBJECT_SCHEMA = {
}, },
"boot_priority": { "boot_priority": {
"description": "QEMU boot priority", "description": "QEMU boot priority",
"enum": ["c", "d", "n", "cn", "cd"] "enum": ["c", "d", "n", "cn", "cd", "dn", "dc", "nc", "nd"]
}, },
"node_directory": { "node_directory": {
"description": "Path to the VM working directory", "description": "Path to the VM working directory",

View File

@ -20,7 +20,7 @@ import time
import logging import logging
import asyncio import asyncio
from ..utils.asyncio import locked_coroutine from ..utils.asyncio import locking
from .ubridge_error import UbridgeError from .ubridge_error import UbridgeError
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -176,7 +176,8 @@ class UBridgeHypervisor:
self._host = host self._host = host
@locked_coroutine @locking
@asyncio.coroutine
def send(self, command): def send(self, command):
""" """
Sends commands to this hypervisor. Sends commands to this hypervisor.

View File

@ -160,32 +160,32 @@ def wait_for_named_pipe_creation(pipe_path, timeout=60):
return return
raise asyncio.TimeoutError() 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): def locking(f):
"""
Method decorator that replace asyncio.coroutine that guarantee
that this specific method of this class instance will not be
executed twice at the same time
"""
@asyncio.coroutine
def new_function(*args, **kwargs):
# In the instance of the class we will store @functools.wraps(f)
# a lock has an attribute. def wrapper(oself, *args, **kwargs):
lock_var_name = "__" + f.__name__ + "_lock" lock_name = "__" + f.__name__ + "_lock"
if not hasattr(args[0], lock_var_name): if not hasattr(oself, lock_name):
setattr(args[0], lock_var_name, asyncio.Lock()) setattr(oself, lock_name, asyncio.Lock())
with (yield from getattr(oself, lock_name)):
return (yield from f(oself, *args, **kwargs))
return wrapper
with (yield from getattr(args[0], lock_var_name)): #FIXME: conservative approach to supported versions, please remove it when we drop the support to Python < 3.4.4
return (yield from f(*args, **kwargs)) try:
from asyncio import ensure_future
return new_function
# It's conservative approach to supported versions, please remove it when we drop the support to Python < 3.4.4
if hasattr(asyncio, 'ensure_future'):
# python>=3.4.4
asyncio_ensure_future = asyncio.ensure_future asyncio_ensure_future = asyncio.ensure_future
else: except ImportError:
# deprecated asyncio_ensure_future = getattr(asyncio, 'async')
asyncio_ensure_future = asyncio.async

View File

@ -214,9 +214,12 @@ class AsyncioTelnetServer:
@asyncio.coroutine @asyncio.coroutine
def close(self): def close(self):
for writer, connection in self._connections.items(): for writer, connection in self._connections.items():
writer.write_eof() try:
yield from writer.drain() writer.write_eof()
yield from writer.drain()
except ConnectionResetError:
continue
@asyncio.coroutine @asyncio.coroutine
def client_connected_hook(self): def client_connected_hook(self):
pass pass
@ -319,6 +322,7 @@ class AsyncioTelnetServer:
else: else:
log.debug("Not supported negotiation sequence, received {} bytes", len(data)) log.debug("Not supported negotiation sequence, received {} bytes", len(data))
@asyncio.coroutine
def _IAC_parser(self, buf, network_reader, network_writer, connection): def _IAC_parser(self, buf, network_reader, network_writer, connection):
""" """
Processes and removes any Telnet commands from the buffer. Processes and removes any Telnet commands from the buffer.
@ -421,9 +425,9 @@ if __name__ == '__main__':
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
process = loop.run_until_complete(asyncio_ensure_future(asyncio.subprocess.create_subprocess_exec("/bin/sh", "-i", process = loop.run_until_complete(asyncio_ensure_future(asyncio.subprocess.create_subprocess_exec("/bin/sh", "-i",
stdout=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT, stderr=asyncio.subprocess.STDOUT,
stdin=asyncio.subprocess.PIPE))) stdin=asyncio.subprocess.PIPE)))
server = AsyncioTelnetServer(reader=process.stdout, writer=process.stdin, binary=False, echo=False) 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) coro = asyncio.start_server(server.run, '127.0.0.1', 4444, loop=loop)

View File

@ -36,8 +36,7 @@ from ..compute import MODULES
from ..compute.port_manager import PortManager from ..compute.port_manager import PortManager
from ..compute.qemu import Qemu from ..compute.qemu import Qemu
from ..controller import Controller from ..controller import Controller
from ..utils.asyncio import asyncio_ensure_future
from gns3server.utils.asyncio import asyncio_ensure_future
# do not delete this import # do not delete this import
import gns3server.handlers import gns3server.handlers
@ -139,7 +138,10 @@ class WebServer:
def signal_handler(signame, *args): def signal_handler(signame, *args):
log.warning("Server has got signal {}, exiting...".format(signame)) 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"] signals = ["SIGTERM", "SIGINT"]
if sys.platform.startswith("win"): if sys.platform.startswith("win"):
@ -304,4 +306,7 @@ class WebServer:
log.warning("TypeError exception in the loop {}".format(e)) log.warning("TypeError exception in the loop {}".format(e))
finally: finally:
if self._loop.is_running(): 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

View File

@ -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.list_images", return_value=[{"image": "ubuntu"}]) as mock_list_images:
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu:latest") 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={ mock.assert_called_with("POST", "containers/create", data={
"Tty": True, "Tty": True,
"OpenStdin": 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.list_images", return_value=[{"image": "ubuntu"}]) as mock_list_images:
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu:16.04") 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={ mock.assert_called_with("POST", "containers/create", data={
"Tty": True, "Tty": True,
"OpenStdin": 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 = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu", console_type="vnc", console=5900)
vm._start_vnc = MagicMock() vm._start_vnc = MagicMock()
vm._display = 42 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={ mock.assert_called_with("POST", "containers/create", data={
"Tty": True, "Tty": True,
"OpenStdin": 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.list_images", return_value=[{"image": "ubuntu"}]):
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: 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) 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] 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 "GNS3_EXTRA_HOSTS=199.199.199.1\ttest\n199.199.199.1\ttest2" in called_kwargs["data"]["Env"]
assert vm._extra_hosts == extra_hosts 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): with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response):
vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu", extra_hosts=extra_hosts) vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu", extra_hosts=extra_hosts)
with pytest.raises(DockerError): 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): 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.list_images", return_value=[{"image": "ubuntu"}]):
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: 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) 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] called_kwargs = mock.call_args[1]
assert len([ e for e in called_kwargs["data"]["Env"] if "GNS3_EXTRA_HOSTS" in e]) == 0 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.list_images", return_value=[{"image": "ubuntu"}]):
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu") 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] called_kwargs = mock.call_args[1]
assert "VAR1=" in called_kwargs["data"]["Env"] assert "VAR1=" in called_kwargs["data"]["Env"]
assert "VAR2=VAL1" 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: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu:latest") vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu:latest")
vm._start_command = "/bin/ls" 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={ mock.assert_called_with("POST", "containers/create", data={
"Tty": True, "Tty": True,
"OpenStdin": 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: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu") vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu")
vm.environment = "YES=1\nNO=0\nGNS3_MAX_ETHERNET=eth2" 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'] == [ assert mock.call_args[1]['data']['Env'] == [
"container=docker", "container=docker",
"GNS3_MAX_ETHERNET=eth0", "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: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu") vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu")
vm.environment = "YES=1\nNO=0\nGNS3_MAX_ETHERNET=eth2\n" 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'] == [ assert mock.call_args[1]['data']['Env'] == [
"container=docker", "container=docker",
"GNS3_MAX_ETHERNET=eth0", "GNS3_MAX_ETHERNET=eth0",
@ -385,7 +385,7 @@ def test_create_image_not_available(loop, project, manager):
vm._get_image_information.side_effect = information 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.DockerVM.pull_image", return_value=True) as mock_pull:
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: 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={ mock.assert_called_with("POST", "containers/create", data={
"Tty": True, "Tty": True,
"OpenStdin": 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: 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"]["Running"] = False
response["State"]["Paused"] = True response["State"]["Paused"] = True
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: 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"]["Running"] = False
response["State"]["Paused"] = False response["State"]["Paused"] = False
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: 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): 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: 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 response["State"]["Running"] = True
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock: 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): def test_pause(loop, vm):
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock: 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") mock.assert_called_with("POST", "containers/e90e34656842/pause")
assert vm.status == "suspended" assert vm.status == "suspended"
@ -471,7 +471,7 @@ def test_pause(loop, vm):
def test_unpause(loop, vm): def test_unpause(loop, vm):
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock: 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") 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() vm._start_console = AsyncioMagicMock()
nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.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.Docker.query") as mock_query: 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") mock_query.assert_called_with("POST", "containers/e90e34656842/start")
vm._add_ubridge_connection.assert_called_once_with(nio, 0) 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 vm.adapters = 1
nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.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.DockerVM._get_container_state", return_value="stopped"):
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: 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 asyncio_patch("gns3server.compute.docker.DockerVM._get_log", return_value='Hello not available') as mock_log:
with pytest.raises(DockerError): 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_query.assert_any_call("POST", "containers/e90e34656842/start")
mock_add_ubridge_connection.assert_called_once_with(nio, 0) 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._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._add_ubridge_connection") as mock_add_ubridge_connection:
with asyncio_patch("gns3server.compute.docker.DockerVM._start_console") as mock_start_console: 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") mock_query.assert_called_with("POST", "containers/e90e34656842/start")
assert mock_add_ubridge_connection.called 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._get_container_state", return_value="paused"):
with asyncio_patch("gns3server.compute.docker.DockerVM.unpause", return_value="paused") as mock: 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 mock.called
assert vm.status == "started" assert vm.status == "started"
@ -563,7 +563,7 @@ def test_start_unpause(loop, vm, manager, free_console_port):
def test_restart(loop, vm): def test_restart(loop, vm):
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock: 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") 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.DockerVM._get_container_state", return_value="running"):
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: 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}) mock_query.assert_called_with("POST", "containers/e90e34656842/stop", params={"t": 5})
assert mock.stop.called assert mock.stop.called
assert vm._ubridge_hypervisor is None 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._get_container_state", return_value="paused"):
with asyncio_patch("gns3server.compute.docker.DockerVM.unpause") as mock_unpause: with asyncio_patch("gns3server.compute.docker.DockerVM.unpause") as mock_unpause:
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: 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}) mock_query.assert_called_with("POST", "containers/e90e34656842/stop", params={"t": 5})
assert mock_unpause.called 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.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.DockerVM._get_container_state", return_value="stopped"):
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock_query: 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("DELETE", "containers/e90e34656842", params={"force": 1, "v": 1})
mock_query.assert_any_call("POST", "containers/create", data={ 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.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.DockerVM._get_container_state", return_value="stopped"):
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock_query: 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.console == original_console
assert vm.aux == original_aux 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.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.DockerVM._get_container_state", return_value="running"):
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock_query: 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("DELETE", "containers/e90e34656842", params={"force": 1, "v": 1})
mock_query.assert_any_call("POST", "containers/create", data={ 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.DockerVM._get_container_state", return_value="stopped"):
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: 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}) 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, "rport": 4343,
"rhost": "127.0.0.1"} "rhost": "127.0.0.1"}
nio = vm.manager.create_nio(nio) 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.DockerVM._get_container_state", return_value="stopped"):
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: 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}) mock_query.assert_called_with("DELETE", "containers/e90e34656842", params={"force": 1, "v": 1})
assert vm._closed is True 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.DockerVM._get_container_state", return_value="stopped"):
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query: 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}) mock_query.assert_called_with("DELETE", "containers/e90e34656842", params={"force": 1, "v": 1})
assert vm._closed is True 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: 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") 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._ubridge_hypervisor = MagicMock()
vm._namespace = 42 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 = [ calls = [
call.send('bridge create bridge0'), call.send('bridge create bridge0'),
@ -792,7 +792,7 @@ def test_add_ubridge_connection_none_nio(loop, vm):
vm._ubridge_hypervisor = MagicMock() vm._ubridge_hypervisor = MagicMock()
vm._namespace = 42 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 = [ calls = [
call.send('bridge create bridge0'), call.send('bridge create bridge0'),
@ -813,7 +813,7 @@ def test_add_ubridge_connection_invalid_adapter_number(loop, vm):
"rhost": "127.0.0.1"} "rhost": "127.0.0.1"}
nio = vm.manager.create_nio(nio) nio = vm.manager.create_nio(nio)
with pytest.raises(DockerError): 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): 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)] interfaces = ["tap-gns3-e{}".format(index) for index in range(4096)]
with patch("psutil.net_if_addrs", return_value=interfaces): 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): def test_adapter_add_nio_binding(vm, loop):
@ -838,7 +838,7 @@ def test_adapter_add_nio_binding(vm, loop):
"rport": 4343, "rport": 4343,
"rhost": "127.0.0.1"} "rhost": "127.0.0.1"}
nio = vm.manager.create_nio(nio) 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 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"} "rhost": "127.0.0.1"}
nio = vm.manager.create_nio(nio) nio = vm.manager.create_nio(nio)
with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="running"): 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 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"} "rhost": "127.0.0.1"}
nio = vm.manager.create_nio(nio) nio = vm.manager.create_nio(nio)
with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="running"): 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 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"} "rhost": "127.0.0.1"}
nio = vm.manager.create_nio(nio) nio = vm.manager.create_nio(nio)
with pytest.raises(DockerError): 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): def test_adapter_remove_nio_binding(vm, loop):
@ -892,10 +892,10 @@ def test_adapter_remove_nio_binding(vm, loop):
"rport": 4343, "rport": 4343,
"rhost": "127.0.0.1"} "rhost": "127.0.0.1"}
nio = vm.manager.create_nio(nio) 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: 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 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 stop bridge0')
delete_ubridge_mock.assert_any_call('bridge remove_nio_udp bridge0 4242 127.0.0.1 4343') 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): def test_adapter_remove_nio_binding_invalid_adapter(vm, loop):
with pytest.raises(DockerError): 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): def test_start_capture(vm, tmpdir, manager, free_console_port, loop):
output_file = str(tmpdir / "test.pcap") 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"}) 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(asyncio.async(vm.start_capture(0, output_file))) loop.run_until_complete(asyncio.ensure_future(vm.start_capture(0, output_file)))
assert vm._ethernet_adapters[0].get_nio(0).capturing 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") 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"}) 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)) loop.run_until_complete(vm.start_capture(0, output_file))
assert vm._ethernet_adapters[0].get_nio(0).capturing 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 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 mock_query.read = read
with asyncio_patch("gns3server.compute.docker.Docker.http_query", return_value=mock_query) as mock: 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={}) 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: with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
vm = DockerVM("test", str(uuid.uuid4()), project, manager, "ubuntu") 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") 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 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("gns3server.compute.docker.docker_vm.wait_for_file_creation") as mock_wait:
with asyncio_patch("asyncio.create_subprocess_exec") as mock_exec: 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 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("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") 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): def test_start_vnc_xvfb_missing(vm, loop):
with pytest.raises(DockerError): 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): def test_start_aux(vm, loop):
with asyncio_patch("asyncio.subprocess.create_subprocess_exec", return_value=MagicMock()) as mock_exec: 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) 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() output_stream = MagicMock()
with asyncio_patch('gns3server.compute.docker.docker_vm.DockerVM.stop'): 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") output_stream.feed_data.assert_called_once_with(b"test")

View File

@ -166,9 +166,9 @@ def test_termination_callback(vm, async_run):
async_run(vm._termination_callback(0)) async_run(vm._termination_callback(0))
assert vm.status == "stopped" 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 action == "node.updated"
assert event == vm assert event == vm
@ -186,7 +186,7 @@ def test_termination_callback_error(vm, tmpdir, async_run):
async_run(vm._termination_callback(1)) async_run(vm._termination_callback(1))
assert vm.status == "stopped" assert vm.status == "stopped"
async_run(queue.get(0)) # Ping async_run(queue.get(1)) # Ping
(action, event, kwargs) = queue.get_nowait() (action, event, kwargs) = queue.get_nowait()
assert action == "node.updated" assert action == "node.updated"

View File

@ -210,5 +210,5 @@ def test_emit(async_run):
def test_update_project(loop): def test_update_project(loop):
variables = [{"name": "TEST", "value": "VAL"}] variables = [{"name": "TEST", "value": "VAL"}]
project = Project(project_id=str(uuid.uuid4())) 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 assert project.variables == variables

View File

@ -56,7 +56,7 @@ def test_vm_invalid_traceng_path(vm, manager, loop):
with pytest.raises(TraceNGError): with pytest.raises(TraceNGError):
nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio) 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.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0e" assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0e"
@ -66,13 +66,13 @@ def test_start(loop, vm, async_run):
process.returncode = None process.returncode = None
with NotificationManager.instance().queue() as queue: 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" vm.ip_address = "192.168.1.1"
with patch("sys.platform", return_value="win"): with patch("sys.platform", return_value="win"):
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._check_requirements", return_value=True): 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: 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(), assert mock_exec.call_args[0] == (vm._traceng_path(),
'-u', '-u',
'-c', '-c',
@ -88,7 +88,7 @@ def test_start(loop, vm, async_run):
'192.168.1.2') '192.168.1.2')
assert vm.is_running() assert vm.is_running()
assert vm.command_line == ' '.join(mock_exec.call_args[0]) 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 action == "node.updated"
assert event == vm assert event == vm
@ -115,15 +115,15 @@ def test_stop(loop, vm, async_run):
assert vm.is_running() assert vm.is_running()
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"): 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 assert vm.is_running() is False
process.terminate.assert_called_with() process.terminate.assert_called_with()
async_run(queue.get(0)) #  Ping async_run(queue.get(1)) #  Ping
async_run(queue.get(0)) #  Started 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 action == "node.updated"
assert event == vm assert event == vm
@ -175,5 +175,5 @@ def test_close(vm, port_manager, loop):
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._check_requirements", return_value=True): with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
vm.start() 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 assert vm.is_running() is False

View File

@ -91,7 +91,7 @@ def test_start(loop, vm, async_run):
process.returncode = None process.returncode = None
with NotificationManager.instance().queue() as queue: 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("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("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') '127.0.0.1')
assert vm.is_running() assert vm.is_running()
assert vm.command_line == ' '.join(mock_exec.call_args[0]) 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 action == "node.updated"
assert event == vm assert event == vm
@ -177,10 +177,10 @@ def test_stop(loop, vm, async_run):
else: else:
process.terminate.assert_called_with() process.terminate.assert_called_with()
async_run(queue.get(0)) #  Ping async_run(queue.get(1)) #  Ping
async_run(queue.get(0)) #  Started 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 action == "node.updated"
assert event == vm assert event == vm

View File

@ -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) monkeypatch.setattr('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.close', lambda self: True)
loop.run_until_complete(instance.unload()) loop.run_until_complete(instance.unload())
srv.close() srv.close()
srv.wait_closed() loop.run_until_complete(srv.wait_closed())
@pytest.fixture @pytest.fixture

View File

@ -277,6 +277,7 @@ def test_json(compute):
"cpu_usage_percent": None, "cpu_usage_percent": None,
"memory_usage_percent": None, "memory_usage_percent": None,
"connected": True, "connected": True,
"last_error": None,
"capabilities": { "capabilities": {
"version": None, "version": None,
"node_types": [] "node_types": []

View File

@ -131,6 +131,7 @@ def test_compute_list(http_controller, controller):
'name': 'My super server', 'name': 'My super server',
'cpu_usage_percent': None, 'cpu_usage_percent': None,
'memory_usage_percent': None, 'memory_usage_percent': None,
'last_error': None,
'capabilities': { 'capabilities': {
'version': None, 'version': None,
'node_types': [] 'node_types': []

View File

@ -21,7 +21,7 @@ import pytest
import sys import sys
from unittest.mock import MagicMock 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 from tests.utils import AsyncioMagicMock
@ -84,7 +84,8 @@ def test_lock_decorator(loop):
def __init__(self): def __init__(self):
self._test_val = 0 self._test_val = 0
@locked_coroutine @locking
@asyncio.coroutine
def method_to_lock(self): def method_to_lock(self):
res = self._test_val res = self._test_val
yield from asyncio.sleep(0.1) yield from asyncio.sleep(0.1)