mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 22:11:14 +02:00
Use pyupgrade with --py36-plus param.
This commit is contained in:
1 parent
a9eb035b7d
commit
f928738bd5
235 files changed
+1501
-1638
No files matched your search
@@ -89,7 +89,7 @@ class Controller:
|
||||
|
||||
protocol = server_config.protocol
|
||||
if self._ssl_context and protocol != "https":
|
||||
log.warning("Protocol changed to 'https' for local compute because SSL is enabled".format(port))
|
||||
log.warning(f"Protocol changed to 'https' for local compute because SSL is enabled")
|
||||
protocol = "https"
|
||||
try:
|
||||
self._local_server = await self.add_compute(compute_id="local",
|
||||
@@ -104,7 +104,7 @@ class Controller:
|
||||
connect=True,
|
||||
ssl_context=self._ssl_context)
|
||||
except ControllerError:
|
||||
log.fatal("Cannot access to the local server, make sure something else is not running on the TCP port {}".format(port))
|
||||
log.fatal(f"Cannot access to the local server, make sure something else is not running on the TCP port {port}")
|
||||
sys.exit(1)
|
||||
|
||||
if computes:
|
||||
@@ -134,7 +134,7 @@ class Controller:
|
||||
log.critical("Could not find the SSL certfile or certkey")
|
||||
raise SystemExit
|
||||
except ssl.SSLError as e:
|
||||
log.critical("SSL error: {}".format(e))
|
||||
log.critical(f"SSL error: {e}")
|
||||
raise SystemExit
|
||||
return ssl_context
|
||||
|
||||
@@ -251,7 +251,7 @@ class Controller:
|
||||
|
||||
if os.path.exists(iourc_path):
|
||||
try:
|
||||
with open(iourc_path, 'r') as f:
|
||||
with open(iourc_path) as f:
|
||||
self._iou_license_settings["iourc_content"] = f.read()
|
||||
log.info(f"iourc file '{iourc_path}' loaded")
|
||||
except OSError as e:
|
||||
@@ -342,7 +342,7 @@ class Controller:
|
||||
|
||||
for compute in self._computes.values():
|
||||
if name and compute.name == name and not force:
|
||||
raise ControllerError('Compute name "{}" already exists'.format(name))
|
||||
raise ControllerError(f'Compute name "{name}" already exists')
|
||||
|
||||
compute = Compute(compute_id=compute_id, controller=self, name=name, **kwargs)
|
||||
self._computes[compute.id] = compute
|
||||
@@ -421,7 +421,7 @@ class Controller:
|
||||
except KeyError:
|
||||
if compute_id == "vm":
|
||||
raise ControllerNotFoundError("Cannot use a node on the GNS3 VM server with the GNS3 VM not configured")
|
||||
raise ControllerNotFoundError("Compute ID {} doesn't exist".format(compute_id))
|
||||
raise ControllerNotFoundError(f"Compute ID {compute_id} doesn't exist")
|
||||
|
||||
def has_compute(self, compute_id):
|
||||
"""
|
||||
@@ -443,9 +443,9 @@ class Controller:
|
||||
for project in self._projects.values():
|
||||
if name and project.name == name:
|
||||
if path and path == project.path:
|
||||
raise ControllerError('Project "{}" already exists in location "{}"'.format(name, path))
|
||||
raise ControllerError(f'Project "{name}" already exists in location "{path}"')
|
||||
else:
|
||||
raise ControllerError('Project "{}" already exists'.format(name))
|
||||
raise ControllerError(f'Project "{name}" already exists')
|
||||
project = Project(project_id=project_id, controller=self, name=name, path=path, **kwargs)
|
||||
self._projects[project.id] = project
|
||||
return self._projects[project.id]
|
||||
@@ -459,7 +459,7 @@ class Controller:
|
||||
try:
|
||||
return self._projects[project_id]
|
||||
except KeyError:
|
||||
raise ControllerNotFoundError("Project ID {} doesn't exist".format(project_id))
|
||||
raise ControllerNotFoundError(f"Project ID {project_id} doesn't exist")
|
||||
|
||||
async def get_loaded_project(self, project_id):
|
||||
"""
|
||||
@@ -521,7 +521,7 @@ class Controller:
|
||||
projects_path = self.projects_directory()
|
||||
|
||||
while True:
|
||||
new_name = "{}-{}".format(base_name, i)
|
||||
new_name = f"{base_name}-{i}"
|
||||
if new_name not in names and not os.path.exists(os.path.join(projects_path, new_name)):
|
||||
break
|
||||
i += 1
|
||||
|
||||
@@ -37,7 +37,7 @@ class Appliance:
|
||||
del self._data["appliance_id"]
|
||||
|
||||
if self.status != 'broken':
|
||||
log.debug('Appliance "{name}" [{id}] loaded'.format(name=self.name, id=self._id))
|
||||
log.debug(f'Appliance "{self.name}" [{self._id}] loaded')
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
|
||||
@@ -90,7 +90,7 @@ class ApplianceManager:
|
||||
path = os.path.join(directory, file)
|
||||
appliance_id = uuid.uuid3(uuid.NAMESPACE_URL, path) # Generate UUID from path to avoid change between reboots
|
||||
try:
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
with open(path, encoding='utf-8') as f:
|
||||
appliance = Appliance(appliance_id, json.load(f), builtin=builtin)
|
||||
json_data = appliance.__json__() # Check if loaded without error
|
||||
if appliance.status != 'broken':
|
||||
@@ -142,20 +142,20 @@ class ApplianceManager:
|
||||
Download a custom appliance symbol from our GitHub registry repository.
|
||||
"""
|
||||
|
||||
symbol_url = "https://raw.githubusercontent.com/GNS3/gns3-registry/master/symbols/{}".format(symbol)
|
||||
symbol_url = f"https://raw.githubusercontent.com/GNS3/gns3-registry/master/symbols/{symbol}"
|
||||
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))
|
||||
log.warning(f"Could not retrieve appliance symbol {symbol} from GitHub due to HTTP error code {response.status}")
|
||||
else:
|
||||
try:
|
||||
symbol_data = await response.read()
|
||||
log.info("Saving {} symbol to {}".format(symbol, destination_path))
|
||||
log.info(f"Saving {symbol} symbol to {destination_path}")
|
||||
with open(destination_path, 'wb') as f:
|
||||
f.write(symbol_data)
|
||||
except asyncio.TimeoutError:
|
||||
log.warning("Timeout while downloading '{}'".format(symbol_url))
|
||||
log.warning(f"Timeout while downloading '{symbol_url}'")
|
||||
except OSError as e:
|
||||
log.warning("Could not write appliance symbol '{}': {}".format(destination_path, e))
|
||||
log.warning(f"Could not write appliance symbol '{destination_path}': {e}")
|
||||
|
||||
@locking
|
||||
async def download_appliances(self):
|
||||
@@ -166,15 +166,15 @@ class ApplianceManager:
|
||||
try:
|
||||
headers = {}
|
||||
if self._appliances_etag:
|
||||
log.info("Checking if appliances are up-to-date (ETag {})".format(self._appliances_etag))
|
||||
log.info(f"Checking if appliances are up-to-date (ETag {self._appliances_etag})")
|
||||
headers["If-None-Match"] = self._appliances_etag
|
||||
|
||||
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))
|
||||
log.info(f"Appliances are already up-to-date (ETag {self._appliances_etag})")
|
||||
return
|
||||
elif response.status != 200:
|
||||
raise ControllerError("Could not retrieve appliances from GitHub due to HTTP error code {}".format(response.status))
|
||||
raise ControllerError(f"Could not retrieve appliances from GitHub due to HTTP error code {response.status}")
|
||||
etag = response.headers.get("ETag")
|
||||
if etag:
|
||||
self._appliances_etag = etag
|
||||
@@ -198,11 +198,11 @@ class ApplianceManager:
|
||||
continue
|
||||
path = os.path.join(appliances_dir, appliance_name)
|
||||
try:
|
||||
log.info("Saving {} file to {}".format(appliance_name, path))
|
||||
log.info(f"Saving {appliance_name} file to {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))
|
||||
raise ControllerError(f"Could not write appliance file '{path}': {e}")
|
||||
downloaded_appliance_files.append(appliance_name)
|
||||
|
||||
# delete old appliance files
|
||||
@@ -212,14 +212,14 @@ class ApplianceManager:
|
||||
continue
|
||||
try:
|
||||
if os.path.isfile(file_path) or os.path.islink(file_path):
|
||||
log.info("Deleting old appliance file {}".format(file_path))
|
||||
log.info(f"Deleting old appliance file {file_path}")
|
||||
os.unlink(file_path)
|
||||
except OSError as e:
|
||||
log.warning("Could not delete old appliance file '{}': {}".format(file_path, e))
|
||||
log.warning(f"Could not delete old appliance file '{file_path}': {e}")
|
||||
continue
|
||||
|
||||
except ValueError as e:
|
||||
raise ControllerError("Could not read appliances information from GitHub: {}".format(e))
|
||||
raise ControllerError(f"Could not read appliances information from GitHub: {e}")
|
||||
|
||||
# download the custom symbols
|
||||
await self.download_custom_symbols()
|
||||
@@ -190,9 +190,9 @@ class Compute:
|
||||
# Due to random user generated by 1.4 it's common to have a very long user
|
||||
if len(user) > 14:
|
||||
user = user[:11] + "..."
|
||||
self._name = "{}://{}@{}:{}".format(self._protocol, user, self._host, self._port)
|
||||
self._name = f"{self._protocol}://{user}@{self._host}:{self._port}"
|
||||
else:
|
||||
self._name = "{}://{}:{}".format(self._protocol, self._host, self._port)
|
||||
self._name = f"{self._protocol}://{self._host}:{self._port}"
|
||||
|
||||
@property
|
||||
def connected(self):
|
||||
@@ -321,10 +321,10 @@ class Compute:
|
||||
:returns: A file stream
|
||||
"""
|
||||
|
||||
url = self._getUrl("/projects/{}/files/{}".format(project.id, path))
|
||||
url = self._getUrl(f"/projects/{project.id}/files/{path}")
|
||||
response = await self._session().request("GET", url, auth=self._auth)
|
||||
if response.status == 404:
|
||||
raise ControllerNotFoundError("{} not found on compute".format(path))
|
||||
raise ControllerNotFoundError(f"{path} not found on compute")
|
||||
return response
|
||||
|
||||
async def download_image(self, image_type, image):
|
||||
@@ -336,10 +336,10 @@ class Compute:
|
||||
:returns: A file stream
|
||||
"""
|
||||
|
||||
url = self._getUrl("/{}/images/{}".format(image_type, image))
|
||||
url = self._getUrl(f"/{image_type}/images/{image}")
|
||||
response = await self._session().request("GET", url, auth=self._auth)
|
||||
if response.status == 404:
|
||||
raise ControllerNotFoundError("{} not found on compute".format(image))
|
||||
raise ControllerNotFoundError(f"{image} not found on compute")
|
||||
return response
|
||||
|
||||
async def http_query(self, method, path, data=None, dont_connect=False, **kwargs):
|
||||
@@ -352,7 +352,7 @@ class Compute:
|
||||
await self._controller.gns3vm.start()
|
||||
await self.connect()
|
||||
if not self._connected and not dont_connect:
|
||||
raise ComputeError("Cannot connect to compute '{}' with request {} {}".format(self._name, method, path))
|
||||
raise ComputeError(f"Cannot connect to compute '{self._name}' with request {method} {path}")
|
||||
response = await self._run_http_query(method, path, data=data, **kwargs)
|
||||
return response
|
||||
|
||||
@@ -373,33 +373,33 @@ class Compute:
|
||||
|
||||
if not self._connected and not self._closed and self.host:
|
||||
try:
|
||||
log.info("Connecting to compute '{}'".format(self._id))
|
||||
log.info(f"Connecting to compute '{self._id}'")
|
||||
response = await self._run_http_query("GET", "/capabilities")
|
||||
except ComputeError as e:
|
||||
log.warning("Cannot connect to compute '{}': {}".format(self._id, e))
|
||||
log.warning(f"Cannot connect to compute '{self._id}': {e}")
|
||||
# Try to reconnect after 5 seconds if server unavailable only if not during tests (otherwise we create a ressource usage bomb)
|
||||
if not hasattr(sys, "_called_from_test") or not sys._called_from_test:
|
||||
if self.id != "local" and self.id != "vm" and not self._controller.compute_has_open_project(self):
|
||||
log.warning("Not reconnecting to compute '{}' because there is no project opened on it".format(self._id))
|
||||
log.warning(f"Not reconnecting to compute '{self._id}' because there is no project opened on it")
|
||||
return
|
||||
self._connection_failure += 1
|
||||
# After 5 failure we close the project using the compute to avoid sync issues
|
||||
if self._connection_failure == 10:
|
||||
log.error("Could not connect to compute '{}' after multiple attempts: {}".format(self._id, e))
|
||||
log.error(f"Could not connect to compute '{self._id}' after multiple attempts: {e}")
|
||||
await self._controller.close_compute_projects(self)
|
||||
asyncio.get_event_loop().call_later(5, lambda: asyncio.ensure_future(self._try_reconnect()))
|
||||
return
|
||||
except web.HTTPNotFound:
|
||||
raise ControllerNotFoundError("The server {} is not a GNS3 server or it's a 1.X server".format(self._id))
|
||||
raise ControllerNotFoundError(f"The server {self._id} is not a GNS3 server or it's a 1.X server")
|
||||
except web.HTTPUnauthorized:
|
||||
raise ControllerUnauthorizedError("Invalid auth for server {}".format(self._id))
|
||||
raise ControllerUnauthorizedError(f"Invalid auth for server {self._id}")
|
||||
except web.HTTPServiceUnavailable:
|
||||
raise ControllerNotFoundError("The server {} is unavailable".format(self._id))
|
||||
raise ControllerNotFoundError(f"The server {self._id} is unavailable")
|
||||
except ValueError:
|
||||
raise ComputeError("Invalid server url for server {}".format(self._id))
|
||||
raise ComputeError(f"Invalid server url for server {self._id}")
|
||||
|
||||
if "version" not in response.json:
|
||||
msg = "The server {} is not a GNS3 server".format(self._id)
|
||||
msg = f"The server {self._id} is not a GNS3 server"
|
||||
log.error(msg)
|
||||
await self._http_session.close()
|
||||
raise ControllerNotFoundError(msg)
|
||||
@@ -426,7 +426,7 @@ class Compute:
|
||||
self._last_error = msg
|
||||
raise ControllerError(msg)
|
||||
else:
|
||||
msg = "{}\nUsing different versions may result in unexpected problems. Please use at your own risk.".format(msg)
|
||||
msg = f"{msg}\nUsing different versions may result in unexpected problems. Please use at your own risk."
|
||||
self._controller.notification.controller_emit("log.warning", {"message": msg})
|
||||
|
||||
self._notifications = asyncio.gather(self._connect_notification())
|
||||
@@ -443,7 +443,7 @@ class Compute:
|
||||
ws_url = self._getUrl("/notifications/ws")
|
||||
try:
|
||||
async with self._session().ws_connect(ws_url, auth=self._auth, heartbeat=10) as ws:
|
||||
log.info("Connected to compute '{}' WebSocket '{}'".format(self._id, ws_url))
|
||||
log.info(f"Connected to compute '{self._id}' WebSocket '{ws_url}'")
|
||||
async for response in ws:
|
||||
if response.type == aiohttp.WSMsgType.TEXT:
|
||||
msg = json.loads(response.data)
|
||||
@@ -462,19 +462,19 @@ class Compute:
|
||||
if response.type == aiohttp.WSMsgType.CLOSE:
|
||||
await ws.close()
|
||||
elif response.type == aiohttp.WSMsgType.ERROR:
|
||||
log.error("Error received on compute '{}' WebSocket '{}': {}".format(self._id, ws_url, ws.exception()))
|
||||
log.error(f"Error received on compute '{self._id}' WebSocket '{ws_url}': {ws.exception()}")
|
||||
elif response.type == aiohttp.WSMsgType.CLOSED:
|
||||
pass
|
||||
break
|
||||
except aiohttp.ClientError as e:
|
||||
log.error("Client response error received on compute '{}' WebSocket '{}': {}".format(self._id, ws_url,e))
|
||||
log.error(f"Client response error received on compute '{self._id}' WebSocket '{ws_url}': {e}")
|
||||
finally:
|
||||
self._connected = False
|
||||
log.info("Connection closed to compute '{}' WebSocket '{}'".format(self._id, ws_url))
|
||||
log.info(f"Connection closed to compute '{self._id}' WebSocket '{ws_url}'")
|
||||
|
||||
# Try to reconnect after 1 second if server unavailable only if not during tests (otherwise we create a ressources usage bomb)
|
||||
if self.id != "local" and not hasattr(sys, "_called_from_test") or not sys._called_from_test:
|
||||
log.info("Reconnecting to to compute '{}' WebSocket '{}'".format(self._id, ws_url))
|
||||
log.info(f"Reconnecting to to compute '{self._id}' WebSocket '{ws_url}'")
|
||||
asyncio.get_event_loop().call_later(1, lambda: asyncio.ensure_future(self.connect()))
|
||||
|
||||
self._cpu_usage_percent = None
|
||||
@@ -492,10 +492,10 @@ class Compute:
|
||||
host = str(ipaddress.IPv6Address(host))
|
||||
if host == "::":
|
||||
host = "::1"
|
||||
host = "[{}]".format(host)
|
||||
host = f"[{host}]"
|
||||
elif host == "0.0.0.0":
|
||||
host = "127.0.0.1"
|
||||
return "{}://{}:{}/v3/compute{}".format(self._protocol, host, self._port, path)
|
||||
return f"{self._protocol}://{host}:{self._port}/v3/compute{path}"
|
||||
|
||||
def get_url(self, path):
|
||||
""" Returns URL for specific path at Compute"""
|
||||
@@ -524,10 +524,10 @@ class Compute:
|
||||
else:
|
||||
data = json.dumps(data).encode("utf-8")
|
||||
try:
|
||||
log.debug("Attempting request to compute: {method} {url} {headers}".format(method=method, url=url, headers=headers))
|
||||
log.debug(f"Attempting request to compute: {method} {url} {headers}")
|
||||
response = await self._session().request(method, url, headers=headers, data=data, auth=self._auth, chunked=chunked, timeout=timeout)
|
||||
except asyncio.TimeoutError:
|
||||
raise ComputeError("Timeout error for {} call to {} after {}s".format(method, url, timeout))
|
||||
raise ComputeError(f"Timeout error for {method} call to {url} after {timeout}s")
|
||||
except (aiohttp.ClientError, aiohttp.ServerDisconnectedError, aiohttp.ClientResponseError, ValueError, KeyError, socket.gaierror) as e:
|
||||
# aiohttp 2.3.1 raises socket.gaierror when cannot find host
|
||||
raise ComputeError(str(e))
|
||||
@@ -546,13 +546,13 @@ class Compute:
|
||||
msg = ""
|
||||
|
||||
if response.status == 401:
|
||||
raise ControllerUnauthorizedError("Invalid authentication for compute {}".format(self.id))
|
||||
raise ControllerUnauthorizedError(f"Invalid authentication for compute {self.id}")
|
||||
elif response.status == 403:
|
||||
raise ControllerForbiddenError(msg)
|
||||
elif response.status == 404:
|
||||
raise ControllerNotFoundError("{} {} not found".format(method, path))
|
||||
raise ControllerNotFoundError(f"{method} {path} not found")
|
||||
elif response.status == 408 or response.status == 504:
|
||||
raise ControllerTimeoutError("{} {} request timeout".format(method, path))
|
||||
raise ControllerTimeoutError(f"{method} {path} request timeout")
|
||||
elif response.status == 409:
|
||||
try:
|
||||
raise ComputeConflict(json.loads(body))
|
||||
@@ -560,11 +560,11 @@ class Compute:
|
||||
except ValueError:
|
||||
raise ControllerError(msg)
|
||||
elif response.status == 500:
|
||||
raise aiohttp.web.HTTPInternalServerError(text="Internal server error {}".format(url))
|
||||
raise aiohttp.web.HTTPInternalServerError(text=f"Internal server error {url}")
|
||||
elif response.status == 503:
|
||||
raise aiohttp.web.HTTPServiceUnavailable(text="Service unavailable {} {}".format(url, body))
|
||||
raise aiohttp.web.HTTPServiceUnavailable(text=f"Service unavailable {url} {body}")
|
||||
else:
|
||||
raise NotImplementedError("{} status code is not supported for {} '{}'".format(response.status, method, url))
|
||||
raise NotImplementedError(f"{response.status} status code is not supported for {method} '{url}'")
|
||||
if body and len(body):
|
||||
if raw:
|
||||
response.body = body
|
||||
@@ -572,7 +572,7 @@ class Compute:
|
||||
try:
|
||||
response.json = json.loads(body)
|
||||
except ValueError:
|
||||
raise ControllerError("The server {} is not a GNS3 server".format(self._id))
|
||||
raise ControllerError(f"The server {self._id} is not a GNS3 server")
|
||||
else:
|
||||
response.json = {}
|
||||
response.body = b""
|
||||
@@ -597,7 +597,7 @@ class Compute:
|
||||
Forward a call to the emulator on compute
|
||||
"""
|
||||
try:
|
||||
action = "/{}/{}".format(type, path)
|
||||
action = f"/{type}/{path}"
|
||||
res = await self.http_query(method, action, data=data, timeout=None)
|
||||
except aiohttp.ServerDisconnectedError:
|
||||
raise ControllerError(f"Connection lost to {self._id} during {method} {action}")
|
||||
@@ -609,7 +609,7 @@ class Compute:
|
||||
"""
|
||||
images = []
|
||||
|
||||
res = await self.http_query("GET", "/{}/images".format(type), timeout=None)
|
||||
res = await self.http_query("GET", f"/{type}/images", timeout=None)
|
||||
images = res.json
|
||||
|
||||
try:
|
||||
@@ -621,14 +621,14 @@ class Compute:
|
||||
else:
|
||||
images = sorted(images, key=itemgetter('image'))
|
||||
except OSError as e:
|
||||
raise ComputeError("Cannot list images: {}".format(str(e)))
|
||||
raise ComputeError(f"Cannot list images: {str(e)}")
|
||||
return images
|
||||
|
||||
async def list_files(self, project):
|
||||
"""
|
||||
List files in the project on computes
|
||||
"""
|
||||
path = "/projects/{}/files".format(project.id)
|
||||
path = f"/projects/{project.id}/files"
|
||||
res = await self.http_query("GET", path, timeout=None)
|
||||
return res.json
|
||||
|
||||
@@ -676,4 +676,4 @@ class Compute:
|
||||
if this_network.overlaps(other_network):
|
||||
return this_interface["ip_address"], other_interface["ip_address"]
|
||||
|
||||
raise ValueError("No common subnet for compute {} and {}".format(self.name, other_compute.name))
|
||||
raise ValueError(f"No common subnet for compute {self.name} and {other_compute.name}")
|
||||
@@ -96,7 +96,7 @@ class Drawing:
|
||||
try:
|
||||
root = ET.fromstring(value)
|
||||
except ET.ParseError as e:
|
||||
log.error("Can't parse SVG: {}".format(e))
|
||||
log.error(f"Can't parse SVG: {e}")
|
||||
return
|
||||
# SVG is the default namespace no need to prefix it
|
||||
ET.register_namespace('xmlns', "http://www.w3.org/2000/svg")
|
||||
@@ -222,4 +222,4 @@ class Drawing:
|
||||
}
|
||||
|
||||
def __repr__(self):
|
||||
return "<gns3server.controller.Drawing {}>".format(self._id)
|
||||
return f"<gns3server.controller.Drawing {self._id}>"
|
||||
@@ -58,7 +58,7 @@ async def export_project(zstream, project, temporary_dir, include_images=False,
|
||||
project.dump()
|
||||
|
||||
if not os.path.exists(project._path):
|
||||
raise ControllerNotFoundError("Project could not be found at '{}'".format(project._path))
|
||||
raise ControllerNotFoundError(f"Project could not be found at '{project._path}'")
|
||||
|
||||
# First we process the .gns3 in order to be sure we don't have an error
|
||||
for file in os.listdir(project._path):
|
||||
@@ -75,7 +75,7 @@ async def export_project(zstream, project, temporary_dir, include_images=False,
|
||||
try:
|
||||
open(path).close()
|
||||
except OSError as e:
|
||||
msg = "Could not export file {}: {}".format(path, e)
|
||||
msg = f"Could not export file {path}: {e}"
|
||||
log.warning(msg)
|
||||
project.emit_notification("log.warning", {"message": msg})
|
||||
continue
|
||||
@@ -85,7 +85,7 @@ async def export_project(zstream, project, temporary_dir, include_images=False,
|
||||
_patch_mtime(path)
|
||||
zstream.write(path, os.path.relpath(path, project._path))
|
||||
except FileNotFoundError as e:
|
||||
log.warning("Cannot export local file: {}".format(e))
|
||||
log.warning(f"Cannot export local file: {e}")
|
||||
continue
|
||||
|
||||
# Export files from remote computes
|
||||
@@ -97,7 +97,7 @@ async def export_project(zstream, project, temporary_dir, include_images=False,
|
||||
log.debug("Downloading file '{}' from compute '{}'".format(compute_file["path"], compute.id))
|
||||
response = await compute.download_file(project, compute_file["path"])
|
||||
if response.status != 200:
|
||||
log.warning("Cannot export file from compute '{}'. Compute returned status code {}.".format(compute.id, response.status))
|
||||
log.warning(f"Cannot export file from compute '{compute.id}'. Compute returned status code {response.status}.")
|
||||
continue
|
||||
(fd, temp_path) = tempfile.mkstemp(dir=temporary_dir)
|
||||
async with aiofiles.open(fd, 'wb') as f:
|
||||
@@ -181,7 +181,7 @@ async def _patch_project_file(project, path, zstream, include_images, keep_compu
|
||||
with open(path) as f:
|
||||
topology = json.load(f)
|
||||
except (OSError, ValueError) as e:
|
||||
raise ControllerError("Project file '{}' cannot be read: {}".format(path, e))
|
||||
raise ControllerError(f"Project file '{path}' cannot be read: {e}")
|
||||
|
||||
if "topology" in topology:
|
||||
if "nodes" in topology["topology"]:
|
||||
@@ -224,14 +224,14 @@ async def _patch_project_file(project, path, zstream, include_images, keep_compu
|
||||
if not keep_compute_id:
|
||||
topology["topology"]["computes"] = [] # Strip compute information because could contain secret info like password
|
||||
|
||||
local_images = set([i['image'] for i in images if i['compute_id'] == 'local'])
|
||||
local_images = {i['image'] for i in images if i['compute_id'] == 'local'}
|
||||
|
||||
for image in local_images:
|
||||
_export_local_image(image, zstream)
|
||||
|
||||
remote_images = set([
|
||||
remote_images = {
|
||||
(i['compute_id'], i['image_type'], i['image'])
|
||||
for i in images if i['compute_id'] != 'local'])
|
||||
for i in images if i['compute_id'] != 'local'}
|
||||
|
||||
for compute_id, image_type, image in remote_images:
|
||||
await _export_remote_images(project, compute_id, image_type, image, zstream, temporary_dir)
|
||||
@@ -274,15 +274,15 @@ async def _export_remote_images(project, compute_id, image_type, image, project_
|
||||
Export specific image from remote compute.
|
||||
"""
|
||||
|
||||
log.debug("Downloading image '{}' from compute '{}'".format(image, compute_id))
|
||||
log.debug(f"Downloading image '{image}' from compute '{compute_id}'")
|
||||
try:
|
||||
compute = [compute for compute in project.computes if compute.id == compute_id][0]
|
||||
except IndexError:
|
||||
raise ControllerNotFoundError("Cannot export image from '{}' compute. Compute doesn't exist.".format(compute_id))
|
||||
raise ControllerNotFoundError(f"Cannot export image from '{compute_id}' compute. Compute doesn't exist.")
|
||||
|
||||
response = await compute.download_image(image_type, image)
|
||||
if response.status != 200:
|
||||
raise ControllerError("Cannot export image from compute '{}'. Compute returned status code {}.".format(compute_id, response.status))
|
||||
raise ControllerError(f"Cannot export image from compute '{compute_id}'. Compute returned status code {response.status}.")
|
||||
|
||||
(fd, temp_path) = tempfile.mkstemp(dir=temporary_dir)
|
||||
async with aiofiles.open(fd, 'wb') as f:
|
||||
@@ -290,7 +290,7 @@ async def _export_remote_images(project, compute_id, image_type, image, project_
|
||||
try:
|
||||
data = await response.content.read(CHUNK_SIZE)
|
||||
except asyncio.TimeoutError:
|
||||
raise ControllerTimeoutError("Timeout when downloading image '{}' from remote compute {}:{}".format(image, compute.host, compute.port))
|
||||
raise ControllerTimeoutError(f"Timeout when downloading image '{image}' from remote compute {compute.host}:{compute.port}")
|
||||
if not data:
|
||||
break
|
||||
await f.write(data)
|
||||
|
||||
@@ -63,7 +63,7 @@ class GNS3VM:
|
||||
download_url = "https://github.com/GNS3/gns3-gui/releases/download/v{version}/GNS3.VM.VMware.Workstation.{version}.zip".format(version=__version__)
|
||||
vmware_info = {
|
||||
"engine_id": "vmware",
|
||||
"description": 'VMware is the recommended choice for best performances.<br>The GNS3 VM can be <a href="{}">downloaded here</a>.'.format(download_url),
|
||||
"description": f'VMware is the recommended choice for best performances.<br>The GNS3 VM can be <a href="{download_url}">downloaded here</a>.',
|
||||
"support_when_exit": True,
|
||||
"support_headless": True,
|
||||
"support_ram": True
|
||||
@@ -77,7 +77,7 @@ class GNS3VM:
|
||||
hyperv_info = {
|
||||
"engine_id": "hyper-v",
|
||||
"name": "Hyper-V",
|
||||
"description": 'Hyper-V support (Windows 10/Server 2016 and above). Nested virtualization must be supported and enabled (Intel processor only)<br>The GNS3 VM can be <a href="{}">downloaded here</a>'.format(download_url),
|
||||
"description": f'Hyper-V support (Windows 10/Server 2016 and above). Nested virtualization must be supported and enabled (Intel processor only)<br>The GNS3 VM can be <a href="{download_url}">downloaded here</a>',
|
||||
"support_when_exit": True,
|
||||
"support_headless": False,
|
||||
"support_ram": True
|
||||
@@ -87,7 +87,7 @@ class GNS3VM:
|
||||
virtualbox_info = {
|
||||
"engine_id": "virtualbox",
|
||||
"name": "VirtualBox",
|
||||
"description": 'VirtualBox support. Nested virtualization for both Intel and AMD processors is supported since version 6.1<br>The GNS3 VM can be <a href="{}">downloaded here</a>'.format(download_url),
|
||||
"description": f'VirtualBox support. Nested virtualization for both Intel and AMD processors is supported since version 6.1<br>The GNS3 VM can be <a href="{download_url}">downloaded here</a>',
|
||||
"support_when_exit": True,
|
||||
"support_headless": True,
|
||||
"support_ram": True
|
||||
@@ -246,7 +246,7 @@ class GNS3VM:
|
||||
elif engine == "remote":
|
||||
self._engines["remote"] = RemoteGNS3VM(self._controller)
|
||||
return self._engines["remote"]
|
||||
raise NotImplementedError("The engine {} for the GNS3 VM is not supported".format(engine))
|
||||
raise NotImplementedError(f"The engine {engine} for the GNS3 VM is not supported")
|
||||
|
||||
def __json__(self):
|
||||
return self._settings
|
||||
@@ -281,14 +281,14 @@ class GNS3VM:
|
||||
# User will receive the error later when they will try to use the node
|
||||
try:
|
||||
compute = await self._controller.add_compute(compute_id="vm",
|
||||
name="GNS3 VM ({})".format(self.current_engine().vmname),
|
||||
name=f"GNS3 VM ({self.current_engine().vmname})",
|
||||
host=None,
|
||||
force=True)
|
||||
compute.set_last_error(str(e))
|
||||
|
||||
except ControllerError:
|
||||
pass
|
||||
log.error("Cannot start the GNS3 VM: {}".format(e))
|
||||
log.error(f"Cannot start the GNS3 VM: {e}")
|
||||
|
||||
async def exit_vm(self):
|
||||
|
||||
@@ -319,7 +319,7 @@ class GNS3VM:
|
||||
engine.headless = self._settings["headless"]
|
||||
engine.port = self._settings["port"]
|
||||
compute = await self._controller.add_compute(compute_id="vm",
|
||||
name="GNS3 VM is starting ({})".format(engine.vmname),
|
||||
name=f"GNS3 VM is starting ({engine.vmname})",
|
||||
host=None,
|
||||
force=True,
|
||||
connect=False)
|
||||
@@ -328,12 +328,12 @@ class GNS3VM:
|
||||
await engine.start()
|
||||
except Exception as e:
|
||||
await self._controller.delete_compute("vm")
|
||||
log.error("Cannot start the GNS3 VM: {}".format(str(e)))
|
||||
await compute.update(name="GNS3 VM ({})".format(engine.vmname))
|
||||
log.error(f"Cannot start the GNS3 VM: {str(e)}")
|
||||
await compute.update(name=f"GNS3 VM ({engine.vmname})")
|
||||
compute.set_last_error(str(e))
|
||||
raise e
|
||||
await compute.connect() # we can connect now that the VM has started
|
||||
await compute.update(name="GNS3 VM ({})".format(engine.vmname),
|
||||
await compute.update(name=f"GNS3 VM ({engine.vmname})",
|
||||
protocol=self.protocol,
|
||||
host=self.ip_address,
|
||||
port=self.port,
|
||||
@@ -357,7 +357,7 @@ class GNS3VM:
|
||||
vm_interface_netmask = interface["netmask"]
|
||||
break
|
||||
if vm_interface_netmask:
|
||||
vm_network = ipaddress.ip_interface("{}/{}".format(compute.host_ip, vm_interface_netmask)).network
|
||||
vm_network = ipaddress.ip_interface(f"{compute.host_ip}/{vm_interface_netmask}").network
|
||||
for compute_id in self._controller.computes:
|
||||
if compute_id == "local":
|
||||
compute = self._controller.get_compute(compute_id)
|
||||
@@ -368,7 +368,7 @@ class GNS3VM:
|
||||
netmask = interface["netmask"]
|
||||
break
|
||||
if netmask:
|
||||
compute_network = ipaddress.ip_interface("{}/{}".format(compute.host_ip, netmask)).network
|
||||
compute_network = ipaddress.ip_interface(f"{compute.host_ip}/{netmask}").network
|
||||
if vm_network.compare_networks(compute_network) != 0:
|
||||
msg = "The GNS3 VM (IP={}, NETWORK={}) is not on the same network as the {} server (IP={}, NETWORK={}), please make sure the local server binding is in the same network as the GNS3 VM".format(self.ip_address,
|
||||
vm_network,
|
||||
@@ -377,9 +377,9 @@ class GNS3VM:
|
||||
compute_network)
|
||||
self._controller.notification.controller_emit("log.warning", {"message": msg})
|
||||
except ComputeError as e:
|
||||
log.warning("Could not check the VM is in the same subnet as the local server: {}".format(e))
|
||||
log.warning(f"Could not check the VM is in the same subnet as the local server: {e}")
|
||||
except ControllerError as e:
|
||||
log.warning("Could not check the VM is in the same subnet as the local server: {}".format(e))
|
||||
log.warning(f"Could not check the VM is in the same subnet as the local server: {e}")
|
||||
|
||||
@locking
|
||||
async def _suspend(self):
|
||||
|
||||
@@ -26,4 +26,4 @@ class GNS3VMError(Exception):
|
||||
return self._message
|
||||
|
||||
def __str__(self):
|
||||
return "GNS3VM: {}".format(self._message)
|
||||
return f"GNS3VM: {self._message}"
|
||||
@@ -55,7 +55,7 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
raise GNS3VMError("Hyper-V is only supported on Windows")
|
||||
|
||||
if sys.getwindowsversion().platform_version[0] < 10:
|
||||
raise GNS3VMError("Windows 10/Windows Server 2016 or a later version is required to run Hyper-V with nested virtualization enabled (version {} detected)".format(sys.getwindowsversion().platform_version[0]))
|
||||
raise GNS3VMError(f"Windows 10/Windows Server 2016 or a later version is required to run Hyper-V with nested virtualization enabled (version {sys.getwindowsversion().platform_version[0]} detected)")
|
||||
|
||||
is_windows_10 = sys.getwindowsversion().platform_version[0] == 10 and sys.getwindowsversion().platform_version[1] == 0
|
||||
|
||||
@@ -69,7 +69,7 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
self._wmi = wmi
|
||||
conn = self._wmi.WMI()
|
||||
except self._wmi.x_wmi as e:
|
||||
raise GNS3VMError("Could not connect to WMI: {}".format(e))
|
||||
raise GNS3VMError(f"Could not connect to WMI: {e}")
|
||||
|
||||
if not conn.Win32_ComputerSystem()[0].HypervisorPresent:
|
||||
raise GNS3VMError("Hyper-V is not installed or activated")
|
||||
@@ -95,7 +95,7 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
try:
|
||||
self._conn = self._wmi.WMI(namespace=r"root\virtualization\v2")
|
||||
except self._wmi.x_wmi as e:
|
||||
raise GNS3VMError("Could not connect to WMI: {}".format(e))
|
||||
raise GNS3VMError(f"Could not connect to WMI: {e}")
|
||||
|
||||
if not self._conn.Msvm_VirtualSystemManagementService():
|
||||
raise GNS3VMError("The Windows account running GNS3 does not have the required permissions for Hyper-V")
|
||||
@@ -114,7 +114,7 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
if nb_vms == 0:
|
||||
return None
|
||||
elif nb_vms > 1:
|
||||
raise GNS3VMError("Duplicate VM name found for {}".format(vm_name))
|
||||
raise GNS3VMError(f"Duplicate VM name found for {vm_name}")
|
||||
else:
|
||||
return vms[0]
|
||||
|
||||
@@ -158,7 +158,7 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
|
||||
available_vcpus = psutil.cpu_count(logical=False)
|
||||
if vcpus > available_vcpus:
|
||||
raise GNS3VMError("You have allocated too many vCPUs for the GNS3 VM! (max available is {} vCPUs)".format(available_vcpus))
|
||||
raise GNS3VMError(f"You have allocated too many vCPUs for the GNS3 VM! (max available is {available_vcpus} vCPUs)")
|
||||
|
||||
try:
|
||||
mem_settings = self._get_vm_resources(self._vm, 'Msvm_MemorySettingData')[0]
|
||||
@@ -175,9 +175,9 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
cpu_settings.ExposeVirtualizationExtensions = True # allow the VM to use nested virtualization
|
||||
self._management.ModifyResourceSettings(ResourceSettings=[cpu_settings.GetText_(1)])
|
||||
|
||||
log.info("GNS3 VM vCPU count set to {} and RAM amount set to {}".format(vcpus, ram))
|
||||
log.info(f"GNS3 VM vCPU count set to {vcpus} and RAM amount set to {ram}")
|
||||
except Exception as e:
|
||||
raise GNS3VMError("Could not set to {} and RAM amount set to {}: {}".format(vcpus, ram, e))
|
||||
raise GNS3VMError(f"Could not set to {vcpus} and RAM amount set to {ram}: {e}")
|
||||
|
||||
async def list(self):
|
||||
"""
|
||||
@@ -193,7 +193,7 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
if vm.ElementName != self._management.SystemName:
|
||||
vms.append({"vmname": vm.ElementName})
|
||||
except self._wmi.x_wmi as e:
|
||||
raise GNS3VMError("Could not list Hyper-V VMs: {}".format(e))
|
||||
raise GNS3VMError(f"Could not list Hyper-V VMs: {e}")
|
||||
return vms
|
||||
|
||||
def _get_wmi_obj(self, path):
|
||||
@@ -211,7 +211,7 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
if not self._vm:
|
||||
self._vm = self._find_vm(self.vmname)
|
||||
if not self._vm:
|
||||
raise GNS3VMError("Could not find Hyper-V VM {}".format(self.vmname))
|
||||
raise GNS3VMError(f"Could not find Hyper-V VM {self.vmname}")
|
||||
job_path, ret = self._vm.RequestStateChange(state)
|
||||
if ret == HyperVGNS3VM._WMI_JOB_STATUS_STARTED:
|
||||
job = self._get_wmi_obj(job_path)
|
||||
@@ -219,9 +219,9 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
await asyncio.sleep(0.1)
|
||||
job = self._get_wmi_obj(job_path)
|
||||
if job.JobState != HyperVGNS3VM._WMI_JOB_STATE_COMPLETED:
|
||||
raise GNS3VMError("Error while changing state: {}".format(job.ErrorSummaryDescription))
|
||||
raise GNS3VMError(f"Error while changing state: {job.ErrorSummaryDescription}")
|
||||
elif ret != 0 or ret != 32775:
|
||||
raise GNS3VMError("Failed to change state to {}".format(state))
|
||||
raise GNS3VMError(f"Failed to change state to {state}")
|
||||
|
||||
async def _is_vm_network_active(self):
|
||||
"""
|
||||
@@ -248,7 +248,7 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
|
||||
self._vm = self._find_vm(self.vmname)
|
||||
if not self._vm:
|
||||
raise GNS3VMError("Could not find Hyper-V VM {}".format(self.vmname))
|
||||
raise GNS3VMError(f"Could not find Hyper-V VM {self.vmname}")
|
||||
|
||||
if not self._is_running():
|
||||
if self.allocate_vcpus_ram:
|
||||
@@ -260,7 +260,7 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
try:
|
||||
await self._set_state(HyperVGNS3VM._HYPERV_VM_STATE_ENABLED)
|
||||
except GNS3VMError as e:
|
||||
raise GNS3VMError("Failed to start the GNS3 VM: {}".format(e))
|
||||
raise GNS3VMError(f"Failed to start the GNS3 VM: {e}")
|
||||
log.info("GNS3 VM has been started")
|
||||
|
||||
# check if VM network is active
|
||||
@@ -296,10 +296,10 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
if guest_ip_address:
|
||||
break
|
||||
elif trial == 0:
|
||||
raise GNS3VMError("Could not find guest IP address for {}".format(self.vmname))
|
||||
raise GNS3VMError(f"Could not find guest IP address for {self.vmname}")
|
||||
await asyncio.sleep(1)
|
||||
self.ip_address = guest_ip_address
|
||||
log.info("GNS3 VM IP address set to {}".format(guest_ip_address))
|
||||
log.info(f"GNS3 VM IP address set to {guest_ip_address}")
|
||||
self.running = True
|
||||
|
||||
async def suspend(self):
|
||||
@@ -310,7 +310,7 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
try:
|
||||
await self._set_state(HyperVGNS3VM._HYPERV_VM_STATE_PAUSED)
|
||||
except GNS3VMError as e:
|
||||
raise GNS3VMError("Failed to suspend the GNS3 VM: {}".format(e))
|
||||
raise GNS3VMError(f"Failed to suspend the GNS3 VM: {e}")
|
||||
log.info("GNS3 VM has been suspended")
|
||||
self.running = False
|
||||
|
||||
@@ -322,6 +322,6 @@ class HyperVGNS3VM(BaseGNS3VM):
|
||||
try:
|
||||
await self._set_state(HyperVGNS3VM._HYPERV_VM_STATE_SHUTDOWN)
|
||||
except GNS3VMError as e:
|
||||
raise GNS3VMError("Failed to stop the GNS3 VM: {}".format(e))
|
||||
raise GNS3VMError(f"Failed to stop the GNS3 VM: {e}")
|
||||
log.info("GNS3 VM has been stopped")
|
||||
self.running = False
|
||||
@@ -58,7 +58,7 @@ class RemoteGNS3VM(BaseGNS3VM):
|
||||
self.user = compute.user
|
||||
self.password = compute.password
|
||||
return
|
||||
raise GNS3VMError("Can't start the GNS3 VM remote VM {} not found".format(self.vmname))
|
||||
raise GNS3VMError(f"Can't start the GNS3 VM remote VM {self.vmname} not found")
|
||||
|
||||
async def suspend(self):
|
||||
"""
|
||||
|
||||
@@ -50,7 +50,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
result = await self._virtualbox_manager.execute(subcommand, args, timeout)
|
||||
return ("\n".join(result))
|
||||
except VirtualBoxError as e:
|
||||
raise GNS3VMError("Error while executing VBoxManage command: {}".format(e))
|
||||
raise GNS3VMError(f"Error while executing VBoxManage command: {e}")
|
||||
|
||||
async def _get_state(self):
|
||||
"""
|
||||
@@ -90,7 +90,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
if not self._system_properties:
|
||||
await self._get_system_properties()
|
||||
if "API version" not in self._system_properties:
|
||||
raise VirtualBoxError("Can't access to VirtualBox API version:\n{}".format(self._system_properties))
|
||||
raise VirtualBoxError(f"Can't access to VirtualBox API version:\n{self._system_properties}")
|
||||
from cpuinfo import get_cpu_info
|
||||
cpu_info = await wait_run_in_executor(get_cpu_info)
|
||||
vendor_id = cpu_info.get('vendor_id_raw')
|
||||
@@ -101,7 +101,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
if parse_version(self._system_properties["API version"]) < parse_version("6_0"):
|
||||
raise VirtualBoxError("VirtualBox version 6.0 or above is required to run the GNS3 VM with nested virtualization enabled on AMD processors")
|
||||
else:
|
||||
log.warning("Could not determine CPU vendor: {}".format(vendor_id))
|
||||
log.warning(f"Could not determine CPU vendor: {vendor_id}")
|
||||
|
||||
async def _look_for_interface(self, network_backend):
|
||||
"""
|
||||
@@ -134,7 +134,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
for info in result.splitlines():
|
||||
if '=' in info:
|
||||
name, value = info.split('=', 1)
|
||||
if name == "hostonlyadapter{}".format(interface_number):
|
||||
if name == f"hostonlyadapter{interface_number}":
|
||||
return value.strip('"')
|
||||
return None
|
||||
|
||||
@@ -217,7 +217,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
await self._check_requirements()
|
||||
return await self._virtualbox_manager.list_vms()
|
||||
except VirtualBoxError as e:
|
||||
raise GNS3VMError("Could not list VirtualBox VMs: {}".format(str(e)))
|
||||
raise GNS3VMError(f"Could not list VirtualBox VMs: {str(e)}")
|
||||
|
||||
async def start(self):
|
||||
"""
|
||||
@@ -229,15 +229,15 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
# get a NAT interface number
|
||||
nat_interface_number = await self._look_for_interface("nat")
|
||||
if nat_interface_number < 0:
|
||||
raise GNS3VMError('VM "{}" must have a NAT interface configured in order to start'.format(self.vmname))
|
||||
raise GNS3VMError(f'VM "{self.vmname}" must have a NAT interface configured in order to start')
|
||||
|
||||
hostonly_interface_number = await self._look_for_interface("hostonly")
|
||||
if hostonly_interface_number < 0:
|
||||
raise GNS3VMError('VM "{}" must have a host-only interface configured in order to start'.format(self.vmname))
|
||||
raise GNS3VMError(f'VM "{self.vmname}" must have a host-only interface configured in order to start')
|
||||
|
||||
vboxnet = await self._look_for_vboxnet(hostonly_interface_number)
|
||||
if vboxnet is None:
|
||||
raise GNS3VMError('A VirtualBox host-only network could not be found on network adapter {} for "{}"'.format(hostonly_interface_number, self._vmname))
|
||||
raise GNS3VMError(f'A VirtualBox host-only network could not be found on network adapter {hostonly_interface_number} for "{self._vmname}"')
|
||||
|
||||
if not (await self._check_vboxnet_exists(vboxnet)):
|
||||
if sys.platform.startswith("win") and vboxnet == "vboxnet0":
|
||||
@@ -245,7 +245,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
# on Windows. Try to patch this with the first available vboxnet we find.
|
||||
first_available_vboxnet = await 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))
|
||||
raise GNS3VMError(f'Please add a VirtualBox host-only network with DHCP enabled and attached it to network adapter {hostonly_interface_number} for "{self._vmname}"')
|
||||
await self.set_hostonly_network(hostonly_interface_number, first_available_vboxnet)
|
||||
vboxnet = first_available_vboxnet
|
||||
else:
|
||||
@@ -254,10 +254,10 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
self._vmname))
|
||||
|
||||
if not (await self._check_dhcp_server(vboxnet)):
|
||||
raise GNS3VMError('DHCP must be enabled on VirtualBox host-only network "{}"'.format(vboxnet))
|
||||
raise GNS3VMError(f'DHCP must be enabled on VirtualBox host-only network "{vboxnet}"')
|
||||
|
||||
vm_state = await self._get_state()
|
||||
log.info('"{}" state is {}'.format(self._vmname, vm_state))
|
||||
log.info(f'"{self._vmname}" state is {vm_state}')
|
||||
|
||||
if vm_state == "poweroff":
|
||||
if self.allocate_vcpus_ram:
|
||||
@@ -285,20 +285,20 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
s.bind((ip_address, 0))
|
||||
api_port = s.getsockname()[1]
|
||||
except OSError as e:
|
||||
raise GNS3VMError("Error while getting random port: {}".format(e))
|
||||
raise GNS3VMError(f"Error while getting random port: {e}")
|
||||
|
||||
if (await self._check_vbox_port_forwarding()):
|
||||
# delete the GNS3VM NAT port forwarding rule if it exists
|
||||
log.info("Removing GNS3VM NAT port forwarding rule from interface {}".format(nat_interface_number))
|
||||
await self._execute("controlvm", [self._vmname, "natpf{}".format(nat_interface_number), "delete", "GNS3VM"])
|
||||
log.info(f"Removing GNS3VM NAT port forwarding rule from interface {nat_interface_number}")
|
||||
await self._execute("controlvm", [self._vmname, f"natpf{nat_interface_number}", "delete", "GNS3VM"])
|
||||
|
||||
# add a GNS3VM NAT port forwarding rule to redirect 127.0.0.1 with random port to the port in the VM
|
||||
log.info("Adding GNS3VM NAT port forwarding rule with port {} to interface {}".format(api_port, nat_interface_number))
|
||||
await self._execute("controlvm", [self._vmname, "natpf{}".format(nat_interface_number),
|
||||
"GNS3VM,tcp,{},{},,{}".format(ip_address, api_port, self.port)])
|
||||
log.info(f"Adding GNS3VM NAT port forwarding rule with port {api_port} to interface {nat_interface_number}")
|
||||
await self._execute("controlvm", [self._vmname, f"natpf{nat_interface_number}",
|
||||
f"GNS3VM,tcp,{ip_address},{api_port},,{self.port}"])
|
||||
|
||||
self.ip_address = await self._get_ip(hostonly_interface_number, api_port)
|
||||
log.info("GNS3 VM has been started with IP {}".format(self.ip_address))
|
||||
log.info(f"GNS3 VM has been started with IP {self.ip_address}")
|
||||
self.running = True
|
||||
|
||||
async def _get_ip(self, hostonly_interface_number, api_port):
|
||||
@@ -329,7 +329,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
pass
|
||||
remaining_try -= 1
|
||||
await asyncio.sleep(1)
|
||||
raise GNS3VMError("Could not find guest IP address for {}".format(self.vmname))
|
||||
raise GNS3VMError(f"Could not find guest IP address for {self.vmname}")
|
||||
|
||||
async def suspend(self):
|
||||
"""
|
||||
@@ -377,7 +377,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
"""
|
||||
|
||||
await self._execute("modifyvm", [self._vmname, "--cpus", str(vcpus)], timeout=3)
|
||||
log.info("GNS3 VM vCPU count set to {}".format(vcpus))
|
||||
log.info(f"GNS3 VM vCPU count set to {vcpus}")
|
||||
|
||||
async def set_ram(self, ram):
|
||||
"""
|
||||
@@ -387,7 +387,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
"""
|
||||
|
||||
await self._execute("modifyvm", [self._vmname, "--memory", str(ram)], timeout=3)
|
||||
log.info("GNS3 VM RAM amount set to {}".format(ram))
|
||||
log.info(f"GNS3 VM RAM amount set to {ram}")
|
||||
|
||||
async def enable_nested_hw_virt(self):
|
||||
"""
|
||||
@@ -405,7 +405,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
:param hostonly_network_name: name of the VirtualBox host-only network
|
||||
"""
|
||||
|
||||
await self._execute("modifyvm", [self._vmname, "--hostonlyadapter{}".format(adapter_number), hostonly_network_name], timeout=3)
|
||||
await self._execute("modifyvm", [self._vmname, f"--hostonlyadapter{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))
|
||||
@@ -49,7 +49,7 @@ class VMwareGNS3VM(BaseGNS3VM):
|
||||
result = await self._vmware_manager.execute(subcommand, args, timeout, log_level=log_level)
|
||||
return (''.join(result))
|
||||
except VMwareError as e:
|
||||
raise GNS3VMError("Error while executing VMware command: {}".format(e))
|
||||
raise GNS3VMError(f"Error while executing VMware command: {e}")
|
||||
|
||||
async def _is_running(self):
|
||||
result = await self._vmware_manager.execute("list", [])
|
||||
@@ -67,13 +67,13 @@ class VMwareGNS3VM(BaseGNS3VM):
|
||||
|
||||
# memory must be a multiple of 4 (VMware requirement)
|
||||
if ram % 4 != 0:
|
||||
raise GNS3VMError("Allocated memory {} for the GNS3 VM must be a multiple of 4".format(ram))
|
||||
raise GNS3VMError(f"Allocated memory {ram} for the GNS3 VM must be a multiple of 4")
|
||||
|
||||
available_vcpus = psutil.cpu_count(logical=True)
|
||||
if not float(vcpus).is_integer():
|
||||
raise GNS3VMError("The allocated vCPUs value is not an integer: {}".format(vcpus))
|
||||
raise GNS3VMError(f"The allocated vCPUs value is not an integer: {vcpus}")
|
||||
if vcpus > available_vcpus:
|
||||
raise GNS3VMError("You have allocated too many vCPUs for the GNS3 VM! (max available is {} vCPUs)".format(available_vcpus))
|
||||
raise GNS3VMError(f"You have allocated too many vCPUs for the GNS3 VM! (max available is {available_vcpus} vCPUs)")
|
||||
|
||||
try:
|
||||
pairs = VMware.parse_vmware_file(self._vmx_path)
|
||||
@@ -84,9 +84,9 @@ class VMwareGNS3VM(BaseGNS3VM):
|
||||
pairs["cpuid.corespersocket"] = str(cores_per_sockets)
|
||||
pairs["memsize"] = str(ram)
|
||||
VMware.write_vmx_file(self._vmx_path, pairs)
|
||||
log.info("GNS3 VM vCPU count set to {} and RAM amount set to {}".format(vcpus, ram))
|
||||
log.info(f"GNS3 VM vCPU count set to {vcpus} and RAM amount set to {ram}")
|
||||
except OSError as e:
|
||||
raise GNS3VMError('Could not read/write VMware VMX file "{}": {}'.format(self._vmx_path, e))
|
||||
raise GNS3VMError(f'Could not read/write VMware VMX file "{self._vmx_path}": {e}')
|
||||
|
||||
async def _set_extra_options(self):
|
||||
try:
|
||||
@@ -103,13 +103,13 @@ class VMwareGNS3VM(BaseGNS3VM):
|
||||
if key not in pairs.keys():
|
||||
pairs[key] = value
|
||||
updated = True
|
||||
log.info("GNS3 VM VMX `{}` set to `{}`".format(key, value))
|
||||
log.info(f"GNS3 VM VMX `{key}` set to `{value}`")
|
||||
|
||||
if updated:
|
||||
VMware.write_vmx_file(self._vmx_path, pairs)
|
||||
log.info("GNS3 VM VMX has been updated.")
|
||||
except OSError as e:
|
||||
raise GNS3VMError('Could not read/write VMware VMX file "{}": {}'.format(self._vmx_path, e))
|
||||
raise GNS3VMError(f'Could not read/write VMware VMX file "{self._vmx_path}": {e}')
|
||||
|
||||
async def list(self):
|
||||
"""
|
||||
@@ -119,7 +119,7 @@ class VMwareGNS3VM(BaseGNS3VM):
|
||||
try:
|
||||
return (await self._vmware_manager.list_vms())
|
||||
except VMwareError as e:
|
||||
raise GNS3VMError("Could not list VMware VMs: {}".format(str(e)))
|
||||
raise GNS3VMError(f"Could not list VMware VMs: {str(e)}")
|
||||
|
||||
async def start(self):
|
||||
"""
|
||||
@@ -134,19 +134,19 @@ class VMwareGNS3VM(BaseGNS3VM):
|
||||
|
||||
# check we have a valid VMX file path
|
||||
if not self._vmx_path:
|
||||
raise GNS3VMError("VMWare VM {} not found".format(self.vmname))
|
||||
raise GNS3VMError(f"VMWare VM {self.vmname} not found")
|
||||
if not os.path.exists(self._vmx_path):
|
||||
raise GNS3VMError("VMware VMX file {} doesn't exist".format(self._vmx_path))
|
||||
raise GNS3VMError(f"VMware VMX file {self._vmx_path} doesn't exist")
|
||||
|
||||
# check if the VMware guest tools are installed
|
||||
vmware_tools_state = await self._execute("checkToolsState", [self._vmx_path])
|
||||
if vmware_tools_state not in ("installed", "running"):
|
||||
raise GNS3VMError("VMware tools are not installed in {}".format(self.vmname))
|
||||
raise GNS3VMError(f"VMware tools are not installed in {self.vmname}")
|
||||
|
||||
try:
|
||||
running = await self._is_running()
|
||||
except VMwareError as e:
|
||||
raise GNS3VMError("Could not list VMware VMs: {}".format(str(e)))
|
||||
raise GNS3VMError(f"Could not list VMware VMs: {str(e)}")
|
||||
if not running:
|
||||
# set the number of vCPUs and amount of RAM
|
||||
if self.allocate_vcpus_ram:
|
||||
@@ -180,12 +180,12 @@ class VMwareGNS3VM(BaseGNS3VM):
|
||||
guest_ip_address = await self._execute("getGuestIPAddress", [self._vmx_path, "-wait"], timeout=120)
|
||||
break
|
||||
except GNS3VMError as e:
|
||||
log.debug("{}".format(e))
|
||||
log.debug(f"{e}")
|
||||
await asyncio.sleep(1)
|
||||
if not guest_ip_address:
|
||||
raise GNS3VMError("Could not find guest IP address for {}".format(self.vmname))
|
||||
raise GNS3VMError(f"Could not find guest IP address for {self.vmname}")
|
||||
self.ip_address = guest_ip_address
|
||||
log.info("GNS3 VM IP address set to {}".format(guest_ip_address))
|
||||
log.info(f"GNS3 VM IP address set to {guest_ip_address}")
|
||||
self.running = True
|
||||
|
||||
async def suspend(self):
|
||||
@@ -198,7 +198,7 @@ class VMwareGNS3VM(BaseGNS3VM):
|
||||
try:
|
||||
await self._execute("suspend", [self._vmx_path])
|
||||
except GNS3VMError as e:
|
||||
log.warning("Error when suspending the VM: {}".format(str(e)))
|
||||
log.warning(f"Error when suspending the VM: {str(e)}")
|
||||
log.info("GNS3 VM has been suspended")
|
||||
self.running = False
|
||||
|
||||
@@ -212,6 +212,6 @@ class VMwareGNS3VM(BaseGNS3VM):
|
||||
try:
|
||||
await self._execute("stop", [self._vmx_path, "soft"])
|
||||
except GNS3VMError as e:
|
||||
log.warning("Error when stopping the VM: {}".format(str(e)))
|
||||
log.warning(f"Error when stopping the VM: {str(e)}")
|
||||
log.info("GNS3 VM has been stopped")
|
||||
self.running = False
|
||||
@@ -257,9 +257,9 @@ async def _import_snapshots(snapshots_path, project_name, project_id):
|
||||
with zipfile.ZipFile(f) as zip_file:
|
||||
await wait_run_in_executor(zip_file.extractall, tmpdir)
|
||||
except OSError as e:
|
||||
raise ControllerError("Cannot open snapshot '{}': {}".format(os.path.basename(snapshot), e))
|
||||
raise ControllerError(f"Cannot open snapshot '{os.path.basename(snapshot)}': {e}")
|
||||
except zipfile.BadZipFile:
|
||||
raise ControllerError("Cannot extract files from snapshot '{}': not a GNS3 project (invalid zip)".format(os.path.basename(snapshot)))
|
||||
raise ControllerError(f"Cannot extract files from snapshot '{os.path.basename(snapshot)}': not a GNS3 project (invalid zip)")
|
||||
|
||||
# patch the topology with the correct project name and ID
|
||||
try:
|
||||
@@ -272,9 +272,9 @@ async def _import_snapshots(snapshots_path, project_name, project_id):
|
||||
with open(topology_file_path, "w+", encoding="utf-8") as f:
|
||||
json.dump(topology, f, indent=4, sort_keys=True)
|
||||
except OSError as e:
|
||||
raise ControllerError("Cannot update snapshot '{}': the project.gns3 file cannot be modified: {}".format(os.path.basename(snapshot), e))
|
||||
raise ControllerError(f"Cannot update snapshot '{os.path.basename(snapshot)}': the project.gns3 file cannot be modified: {e}")
|
||||
except (ValueError, KeyError):
|
||||
raise ControllerError("Cannot update snapshot '{}': the project.gns3 file is corrupted".format(os.path.basename(snapshot)))
|
||||
raise ControllerError(f"Cannot update snapshot '{os.path.basename(snapshot)}': the project.gns3 file is corrupted")
|
||||
|
||||
# write everything back to the original snapshot file
|
||||
try:
|
||||
@@ -287,4 +287,4 @@ async def _import_snapshots(snapshots_path, project_name, project_id):
|
||||
async for chunk in zstream:
|
||||
await f.write(chunk)
|
||||
except OSError as e:
|
||||
raise ControllerError("Cannot update snapshot '{}': the snapshot cannot be recreated: {}".format(os.path.basename(snapshot), e))
|
||||
raise ControllerError(f"Cannot update snapshot '{os.path.basename(snapshot)}': the snapshot cannot be recreated: {e}")
|
||||
@@ -226,7 +226,7 @@ class Link:
|
||||
|
||||
port = node.get_port(adapter_number, port_number)
|
||||
if port is None:
|
||||
raise ControllerNotFoundError("Port {}/{} for {} not found".format(adapter_number, port_number, node.name))
|
||||
raise ControllerNotFoundError(f"Port {adapter_number}/{port_number} for {node.name} not found")
|
||||
if port.link is not None:
|
||||
raise ControllerError("Port is already used")
|
||||
|
||||
@@ -245,11 +245,11 @@ class Link:
|
||||
if other_port is None:
|
||||
raise ControllerNotFoundError("Port {}/{} for {} not found".format(other_node["adapter_number"], other_node["port_number"], other_node["node"].name))
|
||||
if port.link_type != other_port.link_type:
|
||||
raise ControllerError("Connecting a {} interface to a {} interface is not allowed".format(other_port.link_type, port.link_type))
|
||||
raise ControllerError(f"Connecting a {other_port.link_type} interface to a {port.link_type} interface is not allowed")
|
||||
|
||||
if label is None:
|
||||
label = {
|
||||
"text": html.escape("{}/{}".format(adapter_number, port_number)),
|
||||
"text": html.escape(f"{adapter_number}/{port_number}"),
|
||||
"style": "font-family: TypeWriter;font-size: 10.0;font-weight: bold;fill: #000000;fill-opacity: 1.0;"
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ class Node:
|
||||
try:
|
||||
setattr(self, prop, kwargs[prop])
|
||||
except AttributeError as e:
|
||||
log.critical("Cannot set attribute '{}'".format(prop))
|
||||
log.critical(f"Cannot set attribute '{prop}'")
|
||||
raise e
|
||||
else:
|
||||
if prop not in self.CONTROLLER_ONLY_PROPERTIES and kwargs[prop] is not None and kwargs[prop] != "":
|
||||
@@ -292,7 +292,7 @@ class Node:
|
||||
try:
|
||||
self._width, self._height, filetype = self._project.controller.symbols.get_size(val)
|
||||
except (ValueError, OSError) as e:
|
||||
log.error("Could not set symbol: {}".format(e))
|
||||
log.error(f"Could not set symbol: {e}")
|
||||
# If symbol is invalid we replace it by the default
|
||||
self.symbol = ":/symbols/computer.svg"
|
||||
if self._label is None:
|
||||
@@ -384,7 +384,7 @@ class Node:
|
||||
trial = 0
|
||||
while trial != 6:
|
||||
try:
|
||||
response = await self._compute.post("/projects/{}/{}/nodes".format(self._project.id, self._node_type), data=data, timeout=timeout)
|
||||
response = await self._compute.post(f"/projects/{self._project.id}/{self._node_type}/nodes", data=data, timeout=timeout)
|
||||
except ComputeConflict as e:
|
||||
if e.response.get("exception") == "ImageMissingError":
|
||||
res = await self._upload_missing_image(self._node_type, e.response["image"])
|
||||
@@ -532,7 +532,7 @@ class Node:
|
||||
else:
|
||||
await self.post("/start", data=data, timeout=240)
|
||||
except asyncio.TimeoutError:
|
||||
raise ControllerTimeoutError("Timeout when starting {}".format(self._name))
|
||||
raise ControllerTimeoutError(f"Timeout when starting {self._name}")
|
||||
|
||||
async def stop(self):
|
||||
"""
|
||||
@@ -544,7 +544,7 @@ class Node:
|
||||
except (ComputeError, ControllerError):
|
||||
pass
|
||||
except asyncio.TimeoutError:
|
||||
raise ControllerTimeoutError("Timeout when stopping {}".format(self._name))
|
||||
raise ControllerTimeoutError(f"Timeout when stopping {self._name}")
|
||||
|
||||
async def suspend(self):
|
||||
"""
|
||||
@@ -553,7 +553,7 @@ class Node:
|
||||
try:
|
||||
await self.post("/suspend", timeout=240)
|
||||
except asyncio.TimeoutError:
|
||||
raise ControllerTimeoutError("Timeout when reloading {}".format(self._name))
|
||||
raise ControllerTimeoutError(f"Timeout when reloading {self._name}")
|
||||
|
||||
async def reload(self):
|
||||
"""
|
||||
@@ -562,7 +562,7 @@ class Node:
|
||||
try:
|
||||
await self.post("/reload", timeout=240)
|
||||
except asyncio.TimeoutError:
|
||||
raise ControllerTimeoutError("Timeout when reloading {}".format(self._name))
|
||||
raise ControllerTimeoutError(f"Timeout when reloading {self._name}")
|
||||
|
||||
async def reset_console(self):
|
||||
"""
|
||||
@@ -573,25 +573,25 @@ class Node:
|
||||
try:
|
||||
await self.post("/console/reset", timeout=240)
|
||||
except asyncio.TimeoutError:
|
||||
raise ControllerTimeoutError("Timeout when reset console {}".format(self._name))
|
||||
raise ControllerTimeoutError(f"Timeout when reset console {self._name}")
|
||||
|
||||
async def post(self, path, data=None, **kwargs):
|
||||
"""
|
||||
HTTP post on the node
|
||||
"""
|
||||
if data:
|
||||
return (await self._compute.post("/projects/{}/{}/nodes/{}{}".format(self._project.id, self._node_type, self._id, path), data=data, **kwargs))
|
||||
return (await self._compute.post(f"/projects/{self._project.id}/{self._node_type}/nodes/{self._id}{path}", data=data, **kwargs))
|
||||
else:
|
||||
return (await self._compute.post("/projects/{}/{}/nodes/{}{}".format(self._project.id, self._node_type, self._id, path), **kwargs))
|
||||
return (await self._compute.post(f"/projects/{self._project.id}/{self._node_type}/nodes/{self._id}{path}", **kwargs))
|
||||
|
||||
async def put(self, path, data=None, **kwargs):
|
||||
"""
|
||||
HTTP post on the node
|
||||
"""
|
||||
if path is None:
|
||||
path = "/projects/{}/{}/nodes/{}".format(self._project.id, self._node_type, self._id)
|
||||
path = f"/projects/{self._project.id}/{self._node_type}/nodes/{self._id}"
|
||||
else:
|
||||
path = "/projects/{}/{}/nodes/{}{}".format(self._project.id, self._node_type, self._id, path)
|
||||
path = f"/projects/{self._project.id}/{self._node_type}/nodes/{self._id}{path}"
|
||||
if data:
|
||||
return (await self._compute.put(path, data=data, **kwargs))
|
||||
else:
|
||||
@@ -602,9 +602,9 @@ class Node:
|
||||
HTTP post on the node
|
||||
"""
|
||||
if path is None:
|
||||
return await self._compute.delete("/projects/{}/{}/nodes/{}".format(self._project.id, self._node_type, self._id), **kwargs)
|
||||
return await self._compute.delete(f"/projects/{self._project.id}/{self._node_type}/nodes/{self._id}", **kwargs)
|
||||
else:
|
||||
return await self._compute.delete("/projects/{}/{}/nodes/{}{}".format(self._project.id, self._node_type, self._id, path), **kwargs)
|
||||
return await self._compute.delete(f"/projects/{self._project.id}/{self._node_type}/nodes/{self._id}{path}", **kwargs)
|
||||
|
||||
async def _upload_missing_image(self, type, img):
|
||||
"""
|
||||
@@ -615,13 +615,13 @@ class Node:
|
||||
for directory in images_directories(type):
|
||||
image = os.path.join(directory, img)
|
||||
if os.path.exists(image):
|
||||
self.project.emit_notification("log.info", {"message": "Uploading missing image {}".format(img)})
|
||||
self.project.emit_notification("log.info", {"message": f"Uploading missing image {img}"})
|
||||
try:
|
||||
with open(image, 'rb') as f:
|
||||
await self._compute.post("/{}/images/{}".format(self._node_type, os.path.basename(img)), data=f, timeout=None)
|
||||
await self._compute.post(f"/{self._node_type}/images/{os.path.basename(img)}", data=f, timeout=None)
|
||||
except OSError as e:
|
||||
raise ControllerError("Can't upload {}: {}".format(image, str(e)))
|
||||
self.project.emit_notification("log.info", {"message": "Upload finished for {}".format(img)})
|
||||
raise ControllerError(f"Can't upload {image}: {str(e)}")
|
||||
self.project.emit_notification("log.info", {"message": f"Upload finished for {img}"})
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -629,13 +629,13 @@ class Node:
|
||||
"""
|
||||
Compute the idle PC for a dynamips node
|
||||
"""
|
||||
return (await self._compute.get("/projects/{}/{}/nodes/{}/auto_idlepc".format(self._project.id, self._node_type, self._id), timeout=240)).json
|
||||
return (await self._compute.get(f"/projects/{self._project.id}/{self._node_type}/nodes/{self._id}/auto_idlepc", timeout=240)).json
|
||||
|
||||
async def dynamips_idlepc_proposals(self):
|
||||
"""
|
||||
Compute a list of potential idle PC
|
||||
"""
|
||||
return (await self._compute.get("/projects/{}/{}/nodes/{}/idlepc_proposals".format(self._project.id, self._node_type, self._id), timeout=240)).json
|
||||
return (await self._compute.get(f"/projects/{self._project.id}/{self._node_type}/nodes/{self._id}/idlepc_proposals", timeout=240)).json
|
||||
|
||||
def get_port(self, adapter_number, port_number):
|
||||
"""
|
||||
@@ -663,7 +663,7 @@ class Node:
|
||||
atm_port.add(int(dest.split(":")[0]))
|
||||
atm_port = sorted(atm_port)
|
||||
for port in atm_port:
|
||||
self._ports.append(PortFactory("{}".format(port), 0, 0, port, "atm"))
|
||||
self._ports.append(PortFactory(f"{port}", 0, 0, port, "atm"))
|
||||
return
|
||||
|
||||
elif self._node_type == "frame_relay_switch":
|
||||
@@ -674,7 +674,7 @@ class Node:
|
||||
frame_relay_port.add(int(dest.split(":")[0]))
|
||||
frame_relay_port = sorted(frame_relay_port)
|
||||
for port in frame_relay_port:
|
||||
self._ports.append(PortFactory("{}".format(port), 0, 0, port, "frame_relay"))
|
||||
self._ports.append(PortFactory(f"{port}", 0, 0, port, "frame_relay"))
|
||||
return
|
||||
elif self._node_type == "dynamips":
|
||||
self._ports = DynamipsPortFactory(self._properties)
|
||||
@@ -686,14 +686,14 @@ class Node:
|
||||
if custom_adapter["adapter_number"] == adapter_number:
|
||||
custom_adapter_settings = custom_adapter
|
||||
break
|
||||
port_name = "eth{}".format(adapter_number)
|
||||
port_name = f"eth{adapter_number}"
|
||||
port_name = custom_adapter_settings.get("port_name", port_name)
|
||||
self._ports.append(PortFactory(port_name, 0, adapter_number, 0, "ethernet", short_name=port_name))
|
||||
elif self._node_type in ("ethernet_switch", "ethernet_hub"):
|
||||
# Basic node we don't want to have adapter number
|
||||
port_number = 0
|
||||
for port in self._properties.get("ports_mapping", []):
|
||||
self._ports.append(PortFactory(port["name"], 0, 0, port_number, "ethernet", short_name="e{}".format(port_number)))
|
||||
self._ports.append(PortFactory(port["name"], 0, 0, port_number, "ethernet", short_name=f"e{port_number}"))
|
||||
port_number += 1
|
||||
elif self._node_type in ("vpcs", "traceng"):
|
||||
self._ports.append(PortFactory("Ethernet0", 0, 0, 0, "ethernet", short_name="e0"))
|
||||
@@ -706,7 +706,7 @@ class Node:
|
||||
self._ports = StandardPortFactory(self._properties, self._port_by_adapter, self._first_port_name, self._port_name_format, self._port_segment_size, self._custom_adapters)
|
||||
|
||||
def __repr__(self):
|
||||
return "<gns3server.controller.Node {} {}>".format(self._node_type, self._name)
|
||||
return f"<gns3server.controller.Node {self._node_type} {self._name}>"
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Node):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2014 GNS3 Technologies Inc.
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2014 GNS3 Technologies Inc.
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2014 GNS3 Technologies Inc.
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2014 GNS3 Technologies Inc.
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2014 GNS3 Technologies Inc.
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2014 GNS3 Technologies Inc.
|
||||
#
|
||||
@@ -86,8 +85,8 @@ class Port:
|
||||
return self._short_name
|
||||
elif '/' in self._name:
|
||||
return self._name.replace(self.long_name_type(), self.short_name_type())
|
||||
elif self._name.startswith("{}{}".format(self.long_name_type(), self._interface_number)):
|
||||
return self.short_name_type() + "{}".format(self._interface_number)
|
||||
elif self._name.startswith(f"{self.long_name_type()}{self._interface_number}"):
|
||||
return self.short_name_type() + f"{self._interface_number}"
|
||||
return self._name
|
||||
|
||||
@short_name.setter
|
||||
|
||||
@@ -81,7 +81,7 @@ class StandardPortFactory:
|
||||
adapter=adapter_number,
|
||||
**cls._generate_replacement(interface_number, segment_number))
|
||||
except (IndexError, ValueError, KeyError) as e:
|
||||
raise ControllerError("Invalid port name format {}: {}".format(port_name_format, str(e)))
|
||||
raise ControllerError(f"Invalid port name format {port_name_format}: {str(e)}")
|
||||
|
||||
port_name = custom_adapter_settings.get("port_name", port_name)
|
||||
port = PortFactory(port_name, segment_number, adapter_number, port_number, "ethernet")
|
||||
@@ -106,7 +106,7 @@ class StandardPortFactory:
|
||||
if "serial_adapters" in properties:
|
||||
for adapter_number in range(adapter_number, properties["serial_adapters"] + adapter_number):
|
||||
for port_number in range(0, port_by_adapter):
|
||||
ports.append(PortFactory("Serial{}/{}".format(segment_number, port_number), segment_number, adapter_number, port_number, "serial"))
|
||||
ports.append(PortFactory(f"Serial{segment_number}/{port_number}", segment_number, adapter_number, port_number, "serial"))
|
||||
segment_number += 1
|
||||
|
||||
return ports
|
||||
@@ -206,18 +206,18 @@ class DynamipsPortFactory:
|
||||
if properties[name]:
|
||||
port_class = cls.ADAPTER_MATRIX[properties[name]]["port"]
|
||||
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 = f"{port_class.long_name_type()}{adapter_number}/{port_number}"
|
||||
port = port_class(name, adapter_number, adapter_number, port_number)
|
||||
port.short_name = "{}{}/{}".format(port_class.short_name_type(), adapter_number, port_number)
|
||||
port.short_name = f"{port_class.short_name_type()}{adapter_number}/{port_number}"
|
||||
ports.append(port)
|
||||
adapter_number += 1
|
||||
elif name.startswith("wic"):
|
||||
if properties[name]:
|
||||
port_class = cls.WIC_MATRIX[properties[name]]["port"]
|
||||
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 = f"{port_class.long_name_type()}{0}/{display_wic_port_number}"
|
||||
port = port_class(name, 0, 0, wic_port_number)
|
||||
port.short_name = "{}{}/{}".format(port_class.short_name_type(), 0, display_wic_port_number)
|
||||
port.short_name = f"{port_class.short_name_type()}{0}/{display_wic_port_number}"
|
||||
ports.append(port)
|
||||
display_wic_port_number += 1
|
||||
wic_port_number += 1
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2014 GNS3 Technologies Inc.
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2014 GNS3 Technologies Inc.
|
||||
#
|
||||
|
||||
@@ -100,7 +100,7 @@ class Project:
|
||||
# Disallow overwrite of existing project
|
||||
if project_id is None and path is not None:
|
||||
if os.path.exists(path):
|
||||
raise ControllerForbiddenError("The path {} already exists".format(path))
|
||||
raise ControllerForbiddenError(f"The path {path} already exists")
|
||||
else:
|
||||
raise ControllerForbiddenError("Providing a path to create a new project is deprecated.")
|
||||
|
||||
@@ -110,7 +110,7 @@ class Project:
|
||||
try:
|
||||
UUID(project_id, version=4)
|
||||
except ValueError:
|
||||
raise ControllerError("{} is not a valid UUID".format(project_id))
|
||||
raise ControllerError(f"{project_id} is not a valid UUID")
|
||||
self._id = project_id
|
||||
|
||||
if path is None:
|
||||
@@ -130,7 +130,7 @@ class Project:
|
||||
self.dump()
|
||||
|
||||
self._iou_id_lock = asyncio.Lock()
|
||||
log.debug('Project "{name}" [{id}] loaded'.format(name=self.name, id=self._id))
|
||||
log.debug(f'Project "{self.name}" [{self._id}] loaded')
|
||||
|
||||
def emit_notification(self, action, event):
|
||||
"""
|
||||
@@ -161,7 +161,7 @@ class Project:
|
||||
# update on computes
|
||||
for compute in list(self._project_created_on_compute):
|
||||
await compute.put(
|
||||
"/projects/{}".format(self._id), {
|
||||
f"/projects/{self._id}", {
|
||||
"variables": self.variables
|
||||
}
|
||||
)
|
||||
@@ -406,7 +406,7 @@ class Project:
|
||||
try:
|
||||
os.makedirs(path, exist_ok=True)
|
||||
except OSError as e:
|
||||
raise ControllerError("Could not create project directory: {}".format(e))
|
||||
raise ControllerError(f"Could not create project directory: {e}")
|
||||
|
||||
if '"' in path:
|
||||
raise ControllerForbiddenError("You are not allowed to use \" in the project directory path. Not supported by Dynamips.")
|
||||
@@ -473,7 +473,7 @@ class Project:
|
||||
except KeyError as e:
|
||||
raise ControllerError("{" + e.args[0] + "} is not a valid replacement string in the node name")
|
||||
except (ValueError, IndexError) as e:
|
||||
raise ControllerError("{} is not a valid replacement string in the node name".format(base_name))
|
||||
raise ControllerError(f"{base_name} is not a valid replacement string in the node name")
|
||||
if name not in self._allocated_node_names:
|
||||
self._allocated_node_names.add(name)
|
||||
return name
|
||||
@@ -596,7 +596,7 @@ class Project:
|
||||
async def delete_node(self, node_id):
|
||||
node = self.get_node(node_id)
|
||||
if node.locked:
|
||||
raise ControllerError("Node {} cannot be deleted because it is locked".format(node.name))
|
||||
raise ControllerError(f"Node {node.name} cannot be deleted because it is locked")
|
||||
await self.__delete_node_links(node)
|
||||
self.remove_allocated_node_name(node.name)
|
||||
del self._nodes[node.id]
|
||||
@@ -614,7 +614,7 @@ class Project:
|
||||
try:
|
||||
return self._nodes[node_id]
|
||||
except KeyError:
|
||||
raise ControllerNotFoundError("Node ID {} doesn't exist".format(node_id))
|
||||
raise ControllerNotFoundError(f"Node ID {node_id} doesn't exist")
|
||||
|
||||
def _get_closed_data(self, section, id_key):
|
||||
"""
|
||||
@@ -627,10 +627,10 @@ class Project:
|
||||
|
||||
try:
|
||||
path = self._topology_file()
|
||||
with open(path, "r") as f:
|
||||
with open(path) as f:
|
||||
topology = json.load(f)
|
||||
except OSError as e:
|
||||
raise ControllerError("Could not load topology: {}".format(e))
|
||||
raise ControllerError(f"Could not load topology: {e}")
|
||||
|
||||
try:
|
||||
data = {}
|
||||
@@ -638,7 +638,7 @@ class Project:
|
||||
data[elem[id_key]] = elem
|
||||
return data
|
||||
except KeyError:
|
||||
raise ControllerNotFoundError("Section {} not found in the topology".format(section))
|
||||
raise ControllerNotFoundError(f"Section {section} not found in the topology")
|
||||
|
||||
@property
|
||||
def nodes(self):
|
||||
@@ -683,13 +683,13 @@ class Project:
|
||||
try:
|
||||
return self._drawings[drawing_id]
|
||||
except KeyError:
|
||||
raise ControllerNotFoundError("Drawing ID {} doesn't exist".format(drawing_id))
|
||||
raise ControllerNotFoundError(f"Drawing ID {drawing_id} doesn't exist")
|
||||
|
||||
@open_required
|
||||
async def delete_drawing(self, drawing_id):
|
||||
drawing = self.get_drawing(drawing_id)
|
||||
if drawing.locked:
|
||||
raise ControllerError("Drawing ID {} cannot be deleted because it is locked".format(drawing_id))
|
||||
raise ControllerError(f"Drawing ID {drawing_id} cannot be deleted because it is locked")
|
||||
del self._drawings[drawing.id]
|
||||
self.dump()
|
||||
self.emit_notification("drawing.deleted", drawing.__json__())
|
||||
@@ -729,7 +729,7 @@ class Project:
|
||||
try:
|
||||
return self._links[link_id]
|
||||
except KeyError:
|
||||
raise ControllerNotFoundError("Link ID {} doesn't exist".format(link_id))
|
||||
raise ControllerNotFoundError(f"Link ID {link_id} doesn't exist")
|
||||
|
||||
@property
|
||||
def links(self):
|
||||
@@ -755,7 +755,7 @@ class Project:
|
||||
try:
|
||||
return self._snapshots[snapshot_id]
|
||||
except KeyError:
|
||||
raise ControllerNotFoundError("Snapshot ID {} doesn't exist".format(snapshot_id))
|
||||
raise ControllerNotFoundError(f"Snapshot ID {snapshot_id} doesn't exist")
|
||||
|
||||
@open_required
|
||||
async def snapshot(self, name):
|
||||
@@ -766,7 +766,7 @@ class Project:
|
||||
"""
|
||||
|
||||
if name in [snap.name for snap in self._snapshots.values()]:
|
||||
raise ControllerError("The snapshot name {} already exists".format(name))
|
||||
raise ControllerError(f"The snapshot name {name} already exists")
|
||||
snapshot = Snapshot(self, name=name)
|
||||
await snapshot.create()
|
||||
self._snapshots[snapshot.id] = snapshot
|
||||
@@ -783,13 +783,13 @@ class Project:
|
||||
if self._status == "closed" or self._closing:
|
||||
return
|
||||
if self._loading:
|
||||
log.warning("Closing project '{}' ignored because it is being loaded".format(self.name))
|
||||
log.warning(f"Closing project '{self.name}' ignored because it is being loaded")
|
||||
return
|
||||
self._closing = True
|
||||
await self.stop_all()
|
||||
for compute in list(self._project_created_on_compute):
|
||||
try:
|
||||
await compute.post("/projects/{}/close".format(self._id), dont_connect=True)
|
||||
await compute.post(f"/projects/{self._id}/close", dont_connect=True)
|
||||
# We don't care if a compute is down at this step
|
||||
except (ComputeError, ControllerError, TimeoutError):
|
||||
pass
|
||||
@@ -828,10 +828,10 @@ class Project:
|
||||
|
||||
for pic_filename in pictures:
|
||||
path = os.path.join(self.pictures_directory, pic_filename)
|
||||
log.info("Deleting unused picture '{}'".format(path))
|
||||
log.info(f"Deleting unused picture '{path}'")
|
||||
os.remove(path)
|
||||
except OSError as e:
|
||||
log.warning("Could not delete unused pictures: {}".format(e))
|
||||
log.warning(f"Could not delete unused pictures: {e}")
|
||||
|
||||
async def delete(self):
|
||||
|
||||
@@ -840,16 +840,16 @@ class Project:
|
||||
await self.open()
|
||||
except ControllerError as e:
|
||||
# ignore missing images or other conflicts when deleting a project
|
||||
log.warning("Conflict while deleting project: {}".format(e))
|
||||
log.warning(f"Conflict while deleting project: {e}")
|
||||
await self.delete_on_computes()
|
||||
await self.close()
|
||||
try:
|
||||
project_directory = get_default_project_directory()
|
||||
if not os.path.commonprefix([project_directory, self.path]) == project_directory:
|
||||
raise ControllerError("Project '{}' cannot be deleted because it is not in the default project directory: '{}'".format(self._name, project_directory))
|
||||
raise ControllerError(f"Project '{self._name}' cannot be deleted because it is not in the default project directory: '{project_directory}'")
|
||||
shutil.rmtree(self.path)
|
||||
except OSError as e:
|
||||
raise ControllerError("Cannot delete project directory {}: {}".format(self.path, str(e)))
|
||||
raise ControllerError(f"Cannot delete project directory {self.path}: {str(e)}")
|
||||
|
||||
async def delete_on_computes(self):
|
||||
"""
|
||||
@@ -857,7 +857,7 @@ class Project:
|
||||
"""
|
||||
for compute in list(self._project_created_on_compute):
|
||||
if compute.id != "local":
|
||||
await compute.delete("/projects/{}".format(self._id))
|
||||
await compute.delete(f"/projects/{self._id}")
|
||||
self._project_created_on_compute.remove(compute)
|
||||
|
||||
@classmethod
|
||||
@@ -873,7 +873,7 @@ class Project:
|
||||
try:
|
||||
os.makedirs(path, exist_ok=True)
|
||||
except OSError as e:
|
||||
raise ControllerError("Could not create project directory: {}".format(e))
|
||||
raise ControllerError(f"Could not create project directory: {e}")
|
||||
return path
|
||||
|
||||
def _topology_file(self):
|
||||
@@ -971,7 +971,7 @@ class Project:
|
||||
except Exception as e:
|
||||
for compute in list(self._project_created_on_compute):
|
||||
try:
|
||||
await compute.post("/projects/{}/close".format(self._id))
|
||||
await compute.post(f"/projects/{self._id}/close")
|
||||
# We don't care if a compute is down at this step
|
||||
except ComputeError:
|
||||
pass
|
||||
@@ -1043,7 +1043,7 @@ class Project:
|
||||
|
||||
# export the project to a temporary location
|
||||
project_path = os.path.join(tmpdir, "project.gns3p")
|
||||
log.info("Exporting project to '{}'".format(project_path))
|
||||
log.info(f"Exporting project to '{project_path}'")
|
||||
async with aiofiles.open(project_path, 'wb') as f:
|
||||
async for chunk in zstream:
|
||||
await f.write(chunk)
|
||||
@@ -1052,9 +1052,9 @@ class Project:
|
||||
with open(project_path, "rb") as f:
|
||||
project = await import_project(self._controller, str(uuid.uuid4()), f, location=location, name=name, keep_compute_id=True)
|
||||
|
||||
log.info("Project '{}' duplicated in {:.4f} seconds".format(project.name, time.time() - begin))
|
||||
log.info(f"Project '{project.name}' duplicated in {time.time() - begin:.4f} seconds")
|
||||
except (ValueError, OSError, UnicodeEncodeError) as e:
|
||||
raise ControllerError("Cannot duplicate project: {}".format(str(e)))
|
||||
raise ControllerError(f"Cannot duplicate project: {str(e)}")
|
||||
|
||||
if previous_status == "closed":
|
||||
await self.close()
|
||||
@@ -1083,7 +1083,7 @@ class Project:
|
||||
json.dump(topo, f, indent=4, sort_keys=True)
|
||||
shutil.move(path + ".tmp", path)
|
||||
except OSError as e:
|
||||
raise ControllerError("Could not write topology: {}".format(e))
|
||||
raise ControllerError(f"Could not write topology: {e}")
|
||||
|
||||
@open_required
|
||||
async def start_all(self):
|
||||
@@ -1209,4 +1209,4 @@ class Project:
|
||||
}
|
||||
|
||||
def __repr__(self):
|
||||
return "<gns3server.controller.Project {} {}>".format(self._name, self._id)
|
||||
return f"<gns3server.controller.Project {self._name} {self._id}>"
|
||||
@@ -85,13 +85,13 @@ class Snapshot:
|
||||
"""
|
||||
|
||||
if os.path.exists(self.path):
|
||||
raise ControllerError("The snapshot file '{}' already exists".format(self.name))
|
||||
raise ControllerError(f"The snapshot file '{self.name}' already exists")
|
||||
|
||||
snapshot_directory = os.path.join(self._project.path, "snapshots")
|
||||
try:
|
||||
os.makedirs(snapshot_directory, exist_ok=True)
|
||||
except OSError as e:
|
||||
raise ControllerError("Could not create the snapshot directory '{}': {}".format(snapshot_directory, e))
|
||||
raise ControllerError(f"Could not create the snapshot directory '{snapshot_directory}': {e}")
|
||||
|
||||
try:
|
||||
begin = time.time()
|
||||
@@ -102,9 +102,9 @@ class Snapshot:
|
||||
async with aiofiles.open(self.path, 'wb') as f:
|
||||
async for chunk in zstream:
|
||||
await f.write(chunk)
|
||||
log.info("Snapshot '{}' created in {:.4f} seconds".format(self.name, time.time() - begin))
|
||||
log.info(f"Snapshot '{self.name}' created in {time.time() - begin:.4f} seconds")
|
||||
except (ValueError, OSError, RuntimeError) as e:
|
||||
raise ControllerError("Could not create snapshot file '{}': {}".format(self.path, e))
|
||||
raise ControllerError(f"Could not create snapshot file '{self.path}': {e}")
|
||||
|
||||
async def restore(self):
|
||||
"""
|
||||
|
||||
@@ -54,7 +54,7 @@ class Symbols:
|
||||
def theme(self, theme):
|
||||
|
||||
if not self._themes.get(theme):
|
||||
raise ControllerNotFoundError("Could not find symbol theme '{}'".format(theme))
|
||||
raise ControllerNotFoundError(f"Could not find symbol theme '{theme}'")
|
||||
self._current_theme = theme
|
||||
|
||||
def default_symbols(self):
|
||||
@@ -65,10 +65,10 @@ class Symbols:
|
||||
|
||||
theme = self._themes.get(symbol_theme, None)
|
||||
if not theme:
|
||||
raise ControllerNotFoundError("Could not find symbol theme '{}'".format(symbol_theme))
|
||||
raise ControllerNotFoundError(f"Could not find symbol theme '{symbol_theme}'")
|
||||
symbol_path = theme.get(symbol)
|
||||
if symbol_path not in self._symbols_path:
|
||||
log.warning("Default symbol {} was not found".format(symbol_path))
|
||||
log.warning(f"Default symbol {symbol_path} was not found")
|
||||
return None
|
||||
return symbol_path
|
||||
|
||||
@@ -119,7 +119,7 @@ class Symbols:
|
||||
try:
|
||||
os.makedirs(directory, exist_ok=True)
|
||||
except OSError as e:
|
||||
log.error("Could not create symbol directory '{}': {}".format(directory, e))
|
||||
log.error(f"Could not create symbol directory '{directory}': {e}")
|
||||
return None
|
||||
return directory
|
||||
|
||||
@@ -132,12 +132,12 @@ class Symbols:
|
||||
return self._symbols_path[symbol_id]
|
||||
except (OSError, KeyError):
|
||||
# try to return a symbol with the same name from the classic theme
|
||||
symbol = self._symbols_path.get(":/symbols/classic/{}".format(os.path.basename(symbol_id)))
|
||||
symbol = self._symbols_path.get(f":/symbols/classic/{os.path.basename(symbol_id)}")
|
||||
if symbol:
|
||||
return symbol
|
||||
else:
|
||||
# return the default computer symbol
|
||||
log.warning("Could not retrieve symbol '{}', returning default symbol...".format(symbol_id))
|
||||
log.warning(f"Could not retrieve symbol '{symbol_id}', returning default symbol...")
|
||||
return self._symbols_path[":/symbols/classic/computer.svg"]
|
||||
|
||||
def get_size(self, symbol_id):
|
||||
|
||||
@@ -55,7 +55,7 @@ def _check_topology_schema(topo):
|
||||
DynamipsNodeValidation.parse_obj(node.get("properties", {}))
|
||||
|
||||
except pydantic.ValidationError as e:
|
||||
error = "Invalid data in topology file: {}".format(e)
|
||||
error = f"Invalid data in topology file: {e}"
|
||||
log.critical(error)
|
||||
raise ControllerError(error)
|
||||
|
||||
@@ -127,7 +127,7 @@ def load_topology(path):
|
||||
with open(path, encoding="utf-8") as f:
|
||||
topo = json.load(f)
|
||||
except (OSError, UnicodeDecodeError, ValueError) as e:
|
||||
raise ControllerError("Could not load topology {}: {}".format(path, str(e)))
|
||||
raise ControllerError(f"Could not load topology {path}: {str(e)}")
|
||||
|
||||
if topo.get("revision", 0) > GNS3_FILE_FORMAT_REVISION:
|
||||
raise ControllerError("This project was created with more recent version of GNS3 (file revision: {}). Please upgrade GNS3 to version {} or later".format(topo["revision"], topo["version"]))
|
||||
@@ -138,7 +138,7 @@ def load_topology(path):
|
||||
try:
|
||||
shutil.copy(path, path + ".backup{}".format(topo.get("revision", 0)))
|
||||
except OSError as e:
|
||||
raise ControllerError("Can't write backup of the topology {}: {}".format(path, str(e)))
|
||||
raise ControllerError(f"Can't write backup of the topology {path}: {str(e)}")
|
||||
changed = True
|
||||
# update the version because we converted the topology
|
||||
topo["version"] = __version__
|
||||
@@ -189,7 +189,7 @@ def load_topology(path):
|
||||
with open(path, "w+", encoding="utf-8") as f:
|
||||
json.dump(topo, f, indent=4, sort_keys=True)
|
||||
except OSError as e:
|
||||
raise ControllerError("Can't write the topology {}: {}".format(path, str(e)))
|
||||
raise ControllerError(f"Can't write the topology {path}: {str(e)}")
|
||||
return topo
|
||||
|
||||
|
||||
@@ -272,12 +272,12 @@ def _convert_2_0_0_beta_2(topo, topo_path):
|
||||
node_dir = os.path.join(dynamips_dir, node_id)
|
||||
try:
|
||||
os.makedirs(os.path.join(node_dir, "configs"), exist_ok=True)
|
||||
for path in glob.glob(os.path.join(glob.escape(dynamips_dir), "*_i{}_*".format(dynamips_id))):
|
||||
for path in glob.glob(os.path.join(glob.escape(dynamips_dir), f"*_i{dynamips_id}_*")):
|
||||
shutil.move(path, os.path.join(node_dir, os.path.basename(path)))
|
||||
for path in glob.glob(os.path.join(glob.escape(dynamips_dir), "configs", "i{}_*".format(dynamips_id))):
|
||||
for path in glob.glob(os.path.join(glob.escape(dynamips_dir), "configs", f"i{dynamips_id}_*")):
|
||||
shutil.move(path, os.path.join(node_dir, "configs", os.path.basename(path)))
|
||||
except OSError as e:
|
||||
raise ControllerError("Can't convert project {}: {}".format(topo_path, str(e)))
|
||||
raise ControllerError(f"Can't convert project {topo_path}: {str(e)}")
|
||||
return topo
|
||||
|
||||
|
||||
@@ -621,7 +621,7 @@ def _convert_border_style(element):
|
||||
elif border_style == 0:
|
||||
pass # Solid line
|
||||
else:
|
||||
style += 'stroke-dasharray="{}" '.format(QT_DASH_TO_SVG[border_style])
|
||||
style += f'stroke-dasharray="{QT_DASH_TO_SVG[border_style]}" '
|
||||
style += 'stroke="{stroke}" stroke-width="{stroke_width}"'.format(
|
||||
stroke=element.get("border_color", "#000000"),
|
||||
stroke_width=element.get("border_width", 2)
|
||||
@@ -672,7 +672,7 @@ def _create_cloud(node, old_node, icon):
|
||||
except ValueError:
|
||||
raise ControllerError("UDP tunnel using IPV6 is not supported in cloud")
|
||||
port = {
|
||||
"name": "UDP tunnel {}".format(len(ports) + 1),
|
||||
"name": f"UDP tunnel {len(ports) + 1}",
|
||||
"port_number": len(ports) + 1,
|
||||
"type": port_type,
|
||||
"lport": int(lport),
|
||||
|
||||
@@ -50,12 +50,12 @@ class UDPLink(Link):
|
||||
try:
|
||||
(node1_host, node2_host) = await node1.compute.get_ip_on_same_subnet(node2.compute)
|
||||
except ValueError as e:
|
||||
raise ControllerError("Cannot get an IP address on same subnet: {}".format(e))
|
||||
raise ControllerError(f"Cannot get an IP address on same subnet: {e}")
|
||||
|
||||
# Reserve a UDP port on both side
|
||||
response = await node1.compute.post("/projects/{}/ports/udp".format(self._project.id))
|
||||
response = await node1.compute.post(f"/projects/{self._project.id}/ports/udp")
|
||||
self._node1_port = response.json["udp_port"]
|
||||
response = await node2.compute.post("/projects/{}/ports/udp".format(self._project.id))
|
||||
response = await node2.compute.post(f"/projects/{self._project.id}/ports/udp")
|
||||
self._node2_port = response.json["udp_port"]
|
||||
|
||||
node1_filters = {}
|
||||
@@ -75,7 +75,7 @@ class UDPLink(Link):
|
||||
"filters": node1_filters,
|
||||
"suspend": self._suspended
|
||||
})
|
||||
await node1.post("/adapters/{adapter_number}/ports/{port_number}/nio".format(adapter_number=adapter_number1, port_number=port_number1), data=self._link_data[0], timeout=120)
|
||||
await node1.post(f"/adapters/{adapter_number1}/ports/{port_number1}/nio", data=self._link_data[0], timeout=120)
|
||||
|
||||
self._link_data.append({
|
||||
"lport": self._node2_port,
|
||||
@@ -86,10 +86,10 @@ class UDPLink(Link):
|
||||
"suspend": self._suspended
|
||||
})
|
||||
try:
|
||||
await node2.post("/adapters/{adapter_number}/ports/{port_number}/nio".format(adapter_number=adapter_number2, port_number=port_number2), data=self._link_data[1], timeout=120)
|
||||
await node2.post(f"/adapters/{adapter_number2}/ports/{port_number2}/nio", data=self._link_data[1], timeout=120)
|
||||
except Exception as e:
|
||||
# We clean the first NIO
|
||||
await node1.delete("/adapters/{adapter_number}/ports/{port_number}/nio".format(adapter_number=adapter_number1, port_number=port_number1), timeout=120)
|
||||
await node1.delete(f"/adapters/{adapter_number1}/ports/{port_number1}/nio", timeout=120)
|
||||
raise e
|
||||
self._created = True
|
||||
|
||||
@@ -116,14 +116,14 @@ class UDPLink(Link):
|
||||
self._link_data[0]["filters"] = node1_filters
|
||||
self._link_data[0]["suspend"] = self._suspended
|
||||
if node1.node_type not in ("ethernet_switch", "ethernet_hub"):
|
||||
await node1.put("/adapters/{adapter_number}/ports/{port_number}/nio".format(adapter_number=adapter_number1, port_number=port_number1), data=self._link_data[0], timeout=120)
|
||||
await node1.put(f"/adapters/{adapter_number1}/ports/{port_number1}/nio", data=self._link_data[0], timeout=120)
|
||||
|
||||
adapter_number2 = self._nodes[1]["adapter_number"]
|
||||
port_number2 = self._nodes[1]["port_number"]
|
||||
self._link_data[1]["filters"] = node2_filters
|
||||
self._link_data[1]["suspend"] = self._suspended
|
||||
if node2.node_type not in ("ethernet_switch", "ethernet_hub"):
|
||||
await node2.put("/adapters/{adapter_number}/ports/{port_number}/nio".format(adapter_number=adapter_number2, port_number=port_number2), data=self._link_data[1], timeout=221)
|
||||
await node2.put(f"/adapters/{adapter_number2}/ports/{port_number2}/nio", data=self._link_data[1], timeout=221)
|
||||
|
||||
async def delete(self):
|
||||
"""
|
||||
@@ -138,7 +138,7 @@ class UDPLink(Link):
|
||||
except IndexError:
|
||||
return
|
||||
try:
|
||||
await node1.delete("/adapters/{adapter_number}/ports/{port_number}/nio".format(adapter_number=adapter_number1, port_number=port_number1), timeout=120)
|
||||
await node1.delete(f"/adapters/{adapter_number1}/ports/{port_number1}/nio", timeout=120)
|
||||
# If the node is already deleted (user selected multiple element and delete all in the same time)
|
||||
except ControllerNotFoundError:
|
||||
pass
|
||||
@@ -150,7 +150,7 @@ class UDPLink(Link):
|
||||
except IndexError:
|
||||
return
|
||||
try:
|
||||
await node2.delete("/adapters/{adapter_number}/ports/{port_number}/nio".format(adapter_number=adapter_number2, port_number=port_number2), timeout=120)
|
||||
await node2.delete(f"/adapters/{adapter_number2}/ports/{port_number2}/nio", timeout=120)
|
||||
# If the node is already deleted (user selected multiple element and delete all in the same time)
|
||||
except ControllerNotFoundError:
|
||||
pass
|
||||
|
||||
Reference in new issue
Block a user