mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-04 06:21:15 +02:00
Drop Python 3.4 and switch to async / await syntax for asyncio. Fixes #1425
This commit is contained in:
1 parent
8baa480b79
commit
76af98404a
119 files changed
+2432
-3084
No files matched your search
@@ -50,8 +50,7 @@ class Response(aiohttp.web.Response):
|
||||
self.content_length = None
|
||||
super().enable_chunked_encoding()
|
||||
|
||||
@asyncio.coroutine
|
||||
def prepare(self, request):
|
||||
async def prepare(self, request):
|
||||
if log.getEffectiveLevel() == logging.DEBUG:
|
||||
log.info("%s %s", request.method, request.path_qs)
|
||||
log.debug("%s", dict(request.headers))
|
||||
@@ -61,7 +60,7 @@ class Response(aiohttp.web.Response):
|
||||
log.debug(dict(self.headers))
|
||||
if hasattr(self, 'body') and self.body is not None and self.headers["CONTENT-TYPE"] == "application/json":
|
||||
log.debug(json.loads(self.body.decode('utf-8')))
|
||||
return (yield from super().prepare(request))
|
||||
return (await super().prepare(request))
|
||||
|
||||
def html(self, answer):
|
||||
"""
|
||||
@@ -112,8 +111,7 @@ class Response(aiohttp.web.Response):
|
||||
raise aiohttp.web.HTTPBadRequest(text="{}".format(e))
|
||||
self.body = json.dumps(answer, indent=4, sort_keys=True).encode('utf-8')
|
||||
|
||||
@asyncio.coroutine
|
||||
def file(self, path, status=200, set_content_length=True):
|
||||
async def file(self, path, status=200, set_content_length=True):
|
||||
"""
|
||||
Return a file as a response
|
||||
"""
|
||||
@@ -138,14 +136,14 @@ class Response(aiohttp.web.Response):
|
||||
|
||||
try:
|
||||
with open(path, 'rb') as fobj:
|
||||
yield from self.prepare(self._request)
|
||||
await self.prepare(self._request)
|
||||
|
||||
while True:
|
||||
data = fobj.read(4096)
|
||||
if not data:
|
||||
break
|
||||
yield from self.write(data)
|
||||
yield from self.drain()
|
||||
await self.write(data)
|
||||
await self.drain()
|
||||
|
||||
except FileNotFoundError:
|
||||
raise aiohttp.web.HTTPNotFound()
|
||||
|
||||
+11
-14
@@ -36,13 +36,12 @@ from ..crash_report import CrashReport
|
||||
from ..config import Config
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def parse_request(request, input_schema, raw):
|
||||
async def parse_request(request, input_schema, raw):
|
||||
"""Parse body of request and raise HTTP errors in case of problems"""
|
||||
|
||||
request.json = {}
|
||||
if not raw:
|
||||
body = yield from request.read()
|
||||
body = await request.read()
|
||||
if body:
|
||||
try:
|
||||
request.json = json.loads(body.decode('utf-8'))
|
||||
@@ -162,8 +161,7 @@ class Route(object):
|
||||
|
||||
func = asyncio.coroutine(func)
|
||||
|
||||
@asyncio.coroutine
|
||||
def control_schema(request):
|
||||
async def control_schema(request):
|
||||
# This block is executed at each method call
|
||||
server_config = Config.instance().get_section_config("Server")
|
||||
|
||||
@@ -177,12 +175,12 @@ class Route(object):
|
||||
if api_version is None or raw is True:
|
||||
response = Response(request=request, route=route, output_schema=output_schema)
|
||||
|
||||
request = yield from parse_request(request, None, raw)
|
||||
yield from func(request, response)
|
||||
request = await parse_request(request, None, raw)
|
||||
await func(request, response)
|
||||
return response
|
||||
|
||||
# API call
|
||||
request = yield from parse_request(request, input_schema, raw)
|
||||
request = await parse_request(request, input_schema, raw)
|
||||
record_file = server_config.get("record")
|
||||
if record_file:
|
||||
try:
|
||||
@@ -192,7 +190,7 @@ class Route(object):
|
||||
except OSError as e:
|
||||
log.warning("Could not write to the record file {}: {}".format(record_file, e))
|
||||
response = Response(request=request, route=route, output_schema=output_schema)
|
||||
yield from func(request, response)
|
||||
await func(request, response)
|
||||
except aiohttp.web.HTTPBadRequest as e:
|
||||
response = Response(request=request, route=route)
|
||||
response.set_status(e.status)
|
||||
@@ -246,8 +244,7 @@ class Route(object):
|
||||
|
||||
return response
|
||||
|
||||
@asyncio.coroutine
|
||||
def node_concurrency(request):
|
||||
async def node_concurrency(request):
|
||||
"""
|
||||
To avoid strange effect we prevent concurrency
|
||||
between the same instance of the node
|
||||
@@ -264,15 +261,15 @@ class Route(object):
|
||||
cls._node_locks.setdefault(lock_key, {"lock": asyncio.Lock(), "concurrency": 0})
|
||||
cls._node_locks[lock_key]["concurrency"] += 1
|
||||
|
||||
with (yield from cls._node_locks[lock_key]["lock"]):
|
||||
response = yield from control_schema(request)
|
||||
async with cls._node_locks[lock_key]["lock"]:
|
||||
response = await control_schema(request)
|
||||
cls._node_locks[lock_key]["concurrency"] -= 1
|
||||
|
||||
# No more waiting requests, garbage collect the lock
|
||||
if cls._node_locks[lock_key]["concurrency"] <= 0:
|
||||
del cls._node_locks[lock_key]
|
||||
else:
|
||||
response = yield from control_schema(request)
|
||||
response = await control_schema(request)
|
||||
return response
|
||||
|
||||
cls._routes.append((method, route, node_concurrency))
|
||||
|
||||
@@ -39,7 +39,6 @@ from ..compute import MODULES
|
||||
from ..compute.port_manager import PortManager
|
||||
from ..compute.qemu import Qemu
|
||||
from ..controller import Controller
|
||||
from ..utils.asyncio import asyncio_ensure_future
|
||||
|
||||
from gns3server.utils.static import get_static_dir
|
||||
|
||||
@@ -90,8 +89,7 @@ class WebServer:
|
||||
return False
|
||||
return True
|
||||
|
||||
@asyncio.coroutine
|
||||
def shutdown_server(self):
|
||||
async def shutdown_server(self):
|
||||
"""
|
||||
Cleanly shutdown the server.
|
||||
"""
|
||||
@@ -104,25 +102,25 @@ class WebServer:
|
||||
|
||||
if self._server:
|
||||
self._server.close()
|
||||
yield from self._server.wait_closed()
|
||||
await self._server.wait_closed()
|
||||
if self._app:
|
||||
yield from self._app.shutdown()
|
||||
await self._app.shutdown()
|
||||
if self._handler:
|
||||
try:
|
||||
# aiohttp < 2.3
|
||||
yield from self._handler.finish_connections(2) # Parameter is timeout
|
||||
await self._handler.finish_connections(2) # Parameter is timeout
|
||||
except AttributeError:
|
||||
# aiohttp >= 2.3
|
||||
yield from self._handler.shutdown(2) # Parameter is timeout
|
||||
await self._handler.shutdown(2) # Parameter is timeout
|
||||
if self._app:
|
||||
yield from self._app.cleanup()
|
||||
await self._app.cleanup()
|
||||
|
||||
yield from Controller.instance().stop()
|
||||
await Controller.instance().stop()
|
||||
|
||||
for module in MODULES:
|
||||
log.debug("Unloading module {}".format(module.__name__))
|
||||
m = module.instance()
|
||||
yield from m.unload()
|
||||
await m.unload()
|
||||
|
||||
if PortManager.instance().tcp_ports:
|
||||
log.warning("TCP ports are still used {}".format(PortManager.instance().tcp_ports))
|
||||
@@ -133,7 +131,7 @@ class WebServer:
|
||||
for task in asyncio.Task.all_tasks():
|
||||
task.cancel()
|
||||
try:
|
||||
yield from asyncio.wait_for(task, 1)
|
||||
await asyncio.wait_for(task, 1)
|
||||
except BaseException:
|
||||
pass
|
||||
|
||||
@@ -144,7 +142,7 @@ class WebServer:
|
||||
def signal_handler(signame, *args):
|
||||
log.warning("Server has got signal {}, exiting...".format(signame))
|
||||
try:
|
||||
asyncio_ensure_future(self.shutdown_server())
|
||||
asyncio.ensure_future(self.shutdown_server())
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
@@ -179,14 +177,13 @@ class WebServer:
|
||||
log.info("SSL is enabled")
|
||||
return ssl_context
|
||||
|
||||
@asyncio.coroutine
|
||||
def start_shell(self):
|
||||
async def start_shell(self):
|
||||
try:
|
||||
from ptpython.repl import embed
|
||||
except ImportError:
|
||||
log.error("Unable to start a shell: the ptpython module must be installed!")
|
||||
return
|
||||
yield from embed(globals(), locals(), return_asyncio_coroutine=True, patch_stdout=True, history_filename=".gns3_shell_history")
|
||||
await embed(globals(), locals(), return_asyncio_coroutine=True, patch_stdout=True, history_filename=".gns3_shell_history")
|
||||
|
||||
def _exit_handling(self):
|
||||
"""
|
||||
@@ -204,16 +201,15 @@ class WebServer:
|
||||
|
||||
atexit.register(close_asyncio_loop)
|
||||
|
||||
@asyncio.coroutine
|
||||
def _on_startup(self, *args):
|
||||
async def _on_startup(self, *args):
|
||||
"""
|
||||
Called when the HTTP server start
|
||||
"""
|
||||
yield from Controller.instance().start()
|
||||
await Controller.instance().start()
|
||||
# Because with a large image collection
|
||||
# without md5sum already computed we start the
|
||||
# computing with server start
|
||||
asyncio_ensure_future(Qemu.instance().list_images())
|
||||
asyncio.ensure_future(Qemu.instance().list_images())
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
@@ -251,7 +247,7 @@ class WebServer:
|
||||
|
||||
if log.getEffectiveLevel() == logging.DEBUG:
|
||||
# On debug version we enable info that
|
||||
# coroutine is not called in a way await/yield from
|
||||
# coroutine is not called in a way await/await
|
||||
self._loop.set_debug(True)
|
||||
|
||||
for key, val in os.environ.items():
|
||||
@@ -300,7 +296,7 @@ class WebServer:
|
||||
self._exit_handling()
|
||||
|
||||
if server_config.getboolean("shell"):
|
||||
asyncio_ensure_future(self.start_shell())
|
||||
asyncio.ensure_future(self.start_shell())
|
||||
|
||||
try:
|
||||
self._loop.run_forever()
|
||||
|
||||
Reference in new issue
Block a user