mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-04 22:41:12 +02:00
Add HTTP client to reuse the aiohttp session where needed.
Remove unnecessary aiohttp exceptions.
This commit is contained in:
1 parent
36c8920cd1
commit
a92c47b310
17 files changed
+221
-151
No files matched your search
@@ -19,12 +19,12 @@ import os
|
||||
import json
|
||||
import uuid
|
||||
import asyncio
|
||||
import aiohttp
|
||||
|
||||
from .appliance import Appliance
|
||||
from ..config import Config
|
||||
from ..utils.asyncio import locking
|
||||
from ..utils.get_resource import get_resource
|
||||
from ..utils.http_client import HTTPClient
|
||||
from .controller_error import ControllerError
|
||||
|
||||
import logging
|
||||
@@ -142,20 +142,19 @@ class ApplianceManager:
|
||||
"""
|
||||
|
||||
symbol_url = "https://raw.githubusercontent.com/GNS3/gns3-registry/master/symbols/{}".format(symbol)
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(symbol_url) as response:
|
||||
if response.status != 200:
|
||||
log.warning("Could not retrieve appliance symbol {} from GitHub due to HTTP error code {}".format(symbol, response.status))
|
||||
else:
|
||||
try:
|
||||
symbol_data = await response.read()
|
||||
log.info("Saving {} symbol to {}".format(symbol, destination_path))
|
||||
with open(destination_path, 'wb') as f:
|
||||
f.write(symbol_data)
|
||||
except asyncio.TimeoutError:
|
||||
log.warning("Timeout while downloading '{}'".format(symbol_url))
|
||||
except OSError as e:
|
||||
log.warning("Could not write appliance symbol '{}': {}".format(destination_path, e))
|
||||
async with HTTPClient.get(symbol_url) as response:
|
||||
if response.status != 200:
|
||||
log.warning("Could not retrieve appliance symbol {} from GitHub due to HTTP error code {}".format(symbol, response.status))
|
||||
else:
|
||||
try:
|
||||
symbol_data = await response.read()
|
||||
log.info("Saving {} symbol to {}".format(symbol, destination_path))
|
||||
with open(destination_path, 'wb') as f:
|
||||
f.write(symbol_data)
|
||||
except asyncio.TimeoutError:
|
||||
log.warning("Timeout while downloading '{}'".format(symbol_url))
|
||||
except OSError as e:
|
||||
log.warning("Could not write appliance symbol '{}': {}".format(destination_path, e))
|
||||
|
||||
@locking
|
||||
async def download_appliances(self):
|
||||
@@ -168,40 +167,40 @@ class ApplianceManager:
|
||||
if self._appliances_etag:
|
||||
log.info("Checking if appliances are up-to-date (ETag {})".format(self._appliances_etag))
|
||||
headers["If-None-Match"] = self._appliances_etag
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get('https://api.github.com/repos/GNS3/gns3-registry/contents/appliances', headers=headers) as response:
|
||||
if response.status == 304:
|
||||
log.info("Appliances are already up-to-date (ETag {})".format(self._appliances_etag))
|
||||
return
|
||||
elif response.status != 200:
|
||||
raise ControllerError("Could not retrieve appliances from GitHub due to HTTP error code {}".format(response.status))
|
||||
etag = response.headers.get("ETag")
|
||||
if etag:
|
||||
self._appliances_etag = etag
|
||||
from . import Controller
|
||||
Controller.instance().save()
|
||||
json_data = await response.json()
|
||||
appliances_dir = get_resource('appliances')
|
||||
for appliance in json_data:
|
||||
if appliance["type"] == "file":
|
||||
appliance_name = appliance["name"]
|
||||
log.info("Download appliance file from '{}'".format(appliance["download_url"]))
|
||||
async with session.get(appliance["download_url"]) as response:
|
||||
if response.status != 200:
|
||||
log.warning("Could not download '{}' due to HTTP error code {}".format(appliance["download_url"], response.status))
|
||||
continue
|
||||
try:
|
||||
appliance_data = await response.read()
|
||||
except asyncio.TimeoutError:
|
||||
log.warning("Timeout while downloading '{}'".format(appliance["download_url"]))
|
||||
continue
|
||||
path = os.path.join(appliances_dir, appliance_name)
|
||||
try:
|
||||
log.info("Saving {} file to {}".format(appliance_name, path))
|
||||
with open(path, 'wb') as f:
|
||||
f.write(appliance_data)
|
||||
except OSError as e:
|
||||
raise ControllerError("Could not write appliance file '{}': {}".format(path, e))
|
||||
|
||||
async with HTTPClient.get('https://api.github.com/repos/GNS3/gns3-registry/contents/appliances', headers=headers) as response:
|
||||
if response.status == 304:
|
||||
log.info("Appliances are already up-to-date (ETag {})".format(self._appliances_etag))
|
||||
return
|
||||
elif response.status != 200:
|
||||
raise ControllerError("Could not retrieve appliances from GitHub due to HTTP error code {}".format(response.status))
|
||||
etag = response.headers.get("ETag")
|
||||
if etag:
|
||||
self._appliances_etag = etag
|
||||
from . import Controller
|
||||
Controller.instance().save()
|
||||
json_data = await response.json()
|
||||
appliances_dir = get_resource('appliances')
|
||||
for appliance in json_data:
|
||||
if appliance["type"] == "file":
|
||||
appliance_name = appliance["name"]
|
||||
log.info("Download appliance file from '{}'".format(appliance["download_url"]))
|
||||
async with HTTPClient.get(appliance["download_url"]) as response:
|
||||
if response.status != 200:
|
||||
log.warning("Could not download '{}' due to HTTP error code {}".format(appliance["download_url"], response.status))
|
||||
continue
|
||||
try:
|
||||
appliance_data = await response.read()
|
||||
except asyncio.TimeoutError:
|
||||
log.warning("Timeout while downloading '{}'".format(appliance["download_url"]))
|
||||
continue
|
||||
path = os.path.join(appliances_dir, appliance_name)
|
||||
try:
|
||||
log.info("Saving {} file to {}".format(appliance_name, path))
|
||||
with open(path, 'wb') as f:
|
||||
f.write(appliance_data)
|
||||
except OSError as e:
|
||||
raise ControllerError("Could not write appliance file '{}': {}".format(path, e))
|
||||
except ValueError as e:
|
||||
raise ControllerError("Could not read appliances information from GitHub: {}".format(e))
|
||||
|
||||
|
||||
@@ -63,7 +63,9 @@ class Compute:
|
||||
A GNS3 compute.
|
||||
"""
|
||||
|
||||
def __init__(self, compute_id, controller=None, protocol="http", host="localhost", port=3080, user=None, password=None, name=None, console_host=None):
|
||||
def __init__(self, compute_id, controller=None, protocol="http", host="localhost", port=3080, user=None,
|
||||
password=None, name=None, console_host=None):
|
||||
|
||||
self._http_session = None
|
||||
assert controller is not None
|
||||
log.info("Create compute %s", compute_id)
|
||||
@@ -103,14 +105,10 @@ class Compute:
|
||||
|
||||
def _session(self):
|
||||
if self._http_session is None or self._http_session.closed is True:
|
||||
self._http_session = aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=None, force_close=True))
|
||||
connector = aiohttp.TCPConnector(force_close=True)
|
||||
self._http_session = aiohttp.ClientSession(connector=connector)
|
||||
return self._http_session
|
||||
|
||||
#def __del__(self):
|
||||
#
|
||||
# if self._http_session:
|
||||
# self._http_session.close()
|
||||
|
||||
def _set_auth(self, user, password):
|
||||
"""
|
||||
Set authentication parameters
|
||||
@@ -466,7 +464,7 @@ class Compute:
|
||||
elif response.type == aiohttp.WSMsgType.CLOSED:
|
||||
pass
|
||||
break
|
||||
except aiohttp.client_exceptions.ClientResponseError as e:
|
||||
except aiohttp.ClientError as e:
|
||||
log.error("Client response error received on compute '{}' WebSocket '{}': {}".format(self._id, ws_url,e))
|
||||
finally:
|
||||
self._connected = False
|
||||
@@ -503,8 +501,7 @@ class Compute:
|
||||
async def _run_http_query(self, method, path, data=None, timeout=20, raw=False):
|
||||
with async_timeout.timeout(timeout):
|
||||
url = self._getUrl(path)
|
||||
headers = {}
|
||||
headers['content-type'] = 'application/json'
|
||||
headers = {'content-type': 'application/json'}
|
||||
chunked = None
|
||||
if data == {}:
|
||||
data = None
|
||||
@@ -579,7 +576,7 @@ class Compute:
|
||||
return response
|
||||
|
||||
async def get(self, path, **kwargs):
|
||||
return (await self.http_query("GET", path, **kwargs))
|
||||
return await self.http_query("GET", path, **kwargs)
|
||||
|
||||
async def post(self, path, data={}, **kwargs):
|
||||
response = await self.http_query("POST", path, data, **kwargs)
|
||||
@@ -600,15 +597,13 @@ class Compute:
|
||||
action = "/{}/{}".format(type, path)
|
||||
res = await self.http_query(method, action, data=data, timeout=None)
|
||||
except aiohttp.ServerDisconnectedError:
|
||||
log.error("Connection lost to %s during %s %s", self._id, method, action)
|
||||
raise aiohttp.web.HTTPGatewayTimeout()
|
||||
raise ControllerError(f"Connection lost to {self._id} during {method} {action}")
|
||||
return res.json
|
||||
|
||||
async def images(self, type):
|
||||
"""
|
||||
Return the list of images available for this type on the compute node.
|
||||
"""
|
||||
images = []
|
||||
|
||||
res = await self.http_query("GET", "/{}/images".format(type), timeout=None)
|
||||
images = res.json
|
||||
@@ -641,11 +636,11 @@ class Compute:
|
||||
:returns: Tuple (ip_for_this_compute, ip_for_other_compute)
|
||||
"""
|
||||
if other_compute == self:
|
||||
return (self.host_ip, self.host_ip)
|
||||
return self.host_ip, self.host_ip
|
||||
|
||||
# Perhaps the user has correct network gateway, we trust him
|
||||
if (self.host_ip not in ('0.0.0.0', '127.0.0.1') and other_compute.host_ip not in ('0.0.0.0', '127.0.0.1')):
|
||||
return (self.host_ip, other_compute.host_ip)
|
||||
if self.host_ip not in ('0.0.0.0', '127.0.0.1') and other_compute.host_ip not in ('0.0.0.0', '127.0.0.1'):
|
||||
return self.host_ip, other_compute.host_ip
|
||||
|
||||
this_compute_interfaces = await self.interfaces()
|
||||
other_compute_interfaces = await other_compute.interfaces()
|
||||
@@ -675,6 +670,6 @@ class Compute:
|
||||
|
||||
other_network = ipaddress.ip_network("{}/{}".format(other_interface["ip_address"], other_interface["netmask"]), strict=False)
|
||||
if this_network.overlaps(other_network):
|
||||
return (this_interface["ip_address"], other_interface["ip_address"])
|
||||
return this_interface["ip_address"], other_interface["ip_address"]
|
||||
|
||||
raise ValueError("No common subnet for compute {} and {}".format(self.name, other_compute.name))
|
||||
@@ -24,6 +24,7 @@ import socket
|
||||
from .base_gns3_vm import BaseGNS3VM
|
||||
from .gns3_vm_error import GNS3VMError
|
||||
from gns3server.utils import parse_version
|
||||
from gns3server.utils.http_client import HTTPClient
|
||||
from gns3server.utils.asyncio import wait_run_in_executor
|
||||
|
||||
from ...compute.virtualbox import (
|
||||
@@ -305,24 +306,24 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
second to a GNS3 endpoint in order to get the list of the interfaces and
|
||||
their IP and after that match it with VirtualBox host only.
|
||||
"""
|
||||
|
||||
remaining_try = 300
|
||||
while remaining_try > 0:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
try:
|
||||
async with session.get('http://127.0.0.1:{}/v2/compute/network/interfaces'.format(api_port)) as resp:
|
||||
if resp.status < 300:
|
||||
try:
|
||||
json_data = await resp.json()
|
||||
if json_data:
|
||||
for interface in json_data:
|
||||
if "name" in interface and interface["name"] == "eth{}".format(
|
||||
hostonly_interface_number - 1):
|
||||
if "ip_address" in interface and len(interface["ip_address"]) > 0:
|
||||
return interface["ip_address"]
|
||||
except ValueError:
|
||||
pass
|
||||
except (OSError, aiohttp.ClientError, TimeoutError, asyncio.TimeoutError):
|
||||
pass
|
||||
try:
|
||||
async with HTTPClient.get(f"http://127.0.0.1:{api_port}/v2/compute/network/interfaces") as resp:
|
||||
if resp.status < 300:
|
||||
try:
|
||||
json_data = await resp.json()
|
||||
if json_data:
|
||||
for interface in json_data:
|
||||
if "name" in interface and interface["name"] == "eth{}".format(
|
||||
hostonly_interface_number - 1):
|
||||
if "ip_address" in interface and len(interface["ip_address"]) > 0:
|
||||
return interface["ip_address"]
|
||||
except ValueError:
|
||||
pass
|
||||
except (OSError, aiohttp.ClientError, TimeoutError, asyncio.TimeoutError):
|
||||
pass
|
||||
remaining_try -= 1
|
||||
await asyncio.sleep(1)
|
||||
raise GNS3VMError("Could not find guest IP address for {}".format(self.vmname))
|
||||
|
||||
Reference in new issue
Block a user