This commit is contained in:
grossmj 2018-08-25 14:10:47 +07:00
parent ad9b6f42bf
commit 902de3dd47
12 changed files with 57 additions and 42 deletions

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
@ -516,7 +516,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
@ -182,7 +182,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):
""" """
Pull image from docker repository Pull image from docker repository

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
@ -550,7 +550,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

@ -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,7 +27,7 @@ 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__, __version_info__ from ..version import __version__, __version_info__
@ -400,7 +400,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

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 .remote_gns3_vm import RemoteGNS3VM from .remote_gns3_vm import RemoteGNS3VM
@ -265,7 +265,8 @@ class GNS3VM:
except GNS3VMError as e: except GNS3VMError as e:
log.warn(str(e)) log.warn(str(e))
@locked_coroutine @locking
@asyncio.coroutine
def start(self): def start(self):
""" """
Start the GNS3 VM Start the GNS3 VM
@ -339,7 +340,8 @@ class GNS3VM:
except aiohttp.web.HTTPConflict as 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)) 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
@ -351,7 +353,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

@ -36,7 +36,7 @@ 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 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 ..utils.asyncio import asyncio_ensure_future
from .export_project import export_project from .export_project import export_project
@ -525,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.
@ -783,7 +784,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

@ -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

@ -138,26 +138,28 @@ 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 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):
# 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)):
with (yield from getattr(args[0], lock_var_name)): return (yield from f(oself, *args, **kwargs))
return (yield from f(*args, **kwargs)) return wrapper
return new_function
#FIXME: conservative approach to supported versions, please remove it when we drop the support to Python < 3.4.4 #FIXME: conservative approach to supported versions, please remove it when we drop the support to Python < 3.4.4
try: try:

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

@ -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)