Use pyupgrade with --py36-plus param.

This commit is contained in:
grossmj committed 2021-04-13 18:37:58 +09:30
1 parent a9eb035b7d
commit f928738bd5
235 files changed
+1501 -1638

No files matched your search

+10 -10
View File
@@ -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
+1 -1
View File
@@ -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):
+14 -14
View File
@@ -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()
+38 -38
View File
@@ -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}")
+2 -2
View File
@@ -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}>"
+12 -12
View File
@@ -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)
+14 -14
View File
@@ -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}"
+17 -17
View File
@@ -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))
+18 -18
View File
@@ -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
+5 -5
View File
@@ -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}")
+3 -3
View File
@@ -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;"
}
+25 -25
View File
@@ -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
View File
@@ -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.
#
+2 -3
View File
@@ -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
+6 -6
View File
@@ -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
View File
@@ -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.
#
+31 -31
View File
@@ -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}>"
+4 -4
View File
@@ -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):
"""
+6 -6
View File
@@ -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):
+9 -9
View File
@@ -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),
+10 -10
View File
@@ -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