mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-28 11:18:11 +00:00
Refactor asyncio locking system for Python 3.7 support. Ref https://github.com/GNS3/gns3-gui/issues/2566 Ref https://github.com/GNS3/gns3-gui/issues/2568
This commit is contained in:
parent
ad9b6f42bf
commit
902de3dd47
@ -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).
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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]
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user