Some cleaning.

This commit is contained in:
grossmj 2021-04-17 18:36:32 +09:30
parent bad3ef7003
commit 44074ff7c9
22 changed files with 122 additions and 99 deletions

View File

@ -71,7 +71,7 @@ async def get_links(project_id: UUID):
409: {"model": schemas.ErrorMessage, "description": "Could not create link"},
},
)
async def create_link(project_id: UUID, link_data: schemas.Link):
async def create_link(project_id: UUID, link_data: schemas.LinkCreate):
"""
Create a new link.
"""
@ -116,7 +116,7 @@ async def get_link(link: Link = Depends(dep_link)):
@router.put("/{link_id}", response_model=schemas.Link, response_model_exclude_unset=True)
async def update_link(link_data: schemas.Link, link: Link = Depends(dep_link)):
async def update_link(link_data: schemas.LinkUpdate, link: Link = Depends(dep_link)):
"""
Update a link.
"""

View File

@ -40,7 +40,12 @@ class EthernetHub(BaseNode):
def __json__(self):
return {"name": self.name, "usage": self.usage, "node_id": self.id, "project_id": self.project.id}
return {
"name": self.name,
"usage": self.usage,
"node_id": self.id,
"project_id": self.project.id
}
async def create(self):
"""

View File

@ -40,7 +40,12 @@ class EthernetSwitch(BaseNode):
def __json__(self):
return {"name": self.name, "usage": self.usage, "node_id": self.id, "project_id": self.project.id}
return {
"name": self.name,
"usage": self.usage,
"node_id": self.id,
"project_id": self.project.id
}
async def create(self):
"""

View File

@ -67,4 +67,7 @@ class NIOGenericEthernet(NIO):
def __json__(self):
return {"type": "nio_generic_ethernet", "ethernet_device": self._ethernet_device}
return {
"type": "nio_generic_ethernet",
"ethernet_device": self._ethernet_device
}

View File

@ -66,4 +66,7 @@ class NIOLinuxEthernet(NIO):
def __json__(self):
return {"type": "nio_linux_ethernet", "ethernet_device": self._ethernet_device}
return {
"type": "nio_linux_ethernet",
"ethernet_device": self._ethernet_device
}

View File

@ -60,4 +60,7 @@ class NIOTAP(NIO):
def __json__(self):
return {"type": "nio_tap", "tap_device": self._tap_device}
return {
"type": "nio_tap",
"tap_device": self._tap_device
}

View File

@ -128,4 +128,9 @@ class NIOUDP(NIO):
def __json__(self):
return {"type": "nio_udp", "lport": self._lport, "rport": self._rport, "rhost": self._rhost}
return {
"type": "nio_udp",
"lport": self._lport,
"rport": self._rport,
"rhost": self._rhost
}

View File

@ -81,4 +81,8 @@ class NIOUNIX(NIO):
def __json__(self):
return {"type": "nio_unix", "local_file": self._local_file, "remote_file": self._remote_file}
return {
"type": "nio_unix",
"local_file": self._local_file,
"remote_file": self._remote_file
}

View File

@ -81,4 +81,8 @@ class NIOVDE(NIO):
def __json__(self):
return {"type": "nio_vde", "local_file": self._local_file, "control_file": self._control_file}
return {
"type": "nio_vde",
"local_file": self._local_file,
"control_file": self._control_file
}

View File

@ -50,4 +50,7 @@ class NIOEthernet(NIO):
def __json__(self):
return {"type": "nio_ethernet", "ethernet_device": self._ethernet_device}
return {
"type": "nio_ethernet",
"ethernet_device": self._ethernet_device
}

View File

@ -50,4 +50,7 @@ class NIOTAP(NIO):
def __json__(self):
return {"type": "nio_tap", "tap_device": self._tap_device}
return {
"type": "nio_tap",
"tap_device": self._tap_device
}

View File

@ -74,4 +74,9 @@ class NIOUDP(NIO):
def __json__(self):
return {"type": "nio_udp", "lport": self._lport, "rport": self._rport, "rhost": self._rhost}
return {
"type": "nio_udp",
"lport": self._lport,
"rport": self._rport,
"rhost": self._rhost
}

View File

@ -79,7 +79,11 @@ class Project:
def __json__(self):
return {"name": self._name, "project_id": self._id, "variables": self._variables}
return {
"name": self._name,
"project_id": self._id,
"variables": self._variables
}
def is_local(self):

View File

@ -17,14 +17,15 @@
import copy
import uuid
import logging
log = logging.getLogger(__name__)
class Appliance:
def __init__(self, appliance_id, data, builtin=True):
if appliance_id is None:
self._id = str(uuid.uuid4())
elif isinstance(appliance_id, uuid.UUID):

View File

@ -390,7 +390,6 @@ class Node:
data["node_id"] = self._id
if self._node_type == "docker":
timeout = None
else:
timeout = 1200
trial = 0
@ -543,7 +542,7 @@ class Node:
if self.custom_adapters:
data["custom_adapters"] = self.custom_adapters
# None properties are not be send. Because it can mean the emulator doesn't support it
# None properties are not be sent because it can mean the emulator doesn't support it
for key in list(data.keys()):
if data[key] is None or data[key] is {} or key in self.CONTROLLER_ONLY_PROPERTIES:
del data[key]
@ -628,7 +627,7 @@ class Node:
async def put(self, path, data=None, **kwargs):
"""
HTTP post on the node
HTTP put on the node
"""
if path is None:
path = f"/projects/{self._project.id}/{self._node_type}/nodes/{self._id}"
@ -780,11 +779,10 @@ class Node:
def __json__(self, topology_dump=False):
"""
:param topology_dump: Filter to keep only properties require for saving on disk
:param topology_dump: Filter to keep only properties required for saving on disk
"""
if topology_dump:
return {
topology = {
"compute_id": str(self._compute.id),
"node_id": self._id,
"node_type": self._node_type,
@ -808,35 +806,18 @@ class Node:
"port_segment_size": self._port_segment_size,
"first_port_name": self._first_port_name,
"custom_adapters": self._custom_adapters,
}
return {
"compute_id": str(self._compute.id),
"project_id": self._project.id,
"node_id": self._id,
"template_id": self._template_id,
"node_type": self._node_type,
"node_directory": self._node_directory,
"name": self._name,
"console": self._console,
"console_host": str(self._compute.console_host),
"console_type": self._console_type,
"aux": self._aux,
"aux_type": self._aux_type,
"console_auto_start": self._console_auto_start,
"command_line": self._command_line,
"properties": self._properties,
"status": self._status,
"label": self._label,
"x": self._x,
"y": self._y,
"z": self._z,
"locked": self._locked,
"width": self._width,
"height": self._height,
"symbol": self._symbol,
"port_name_format": self._port_name_format,
"port_segment_size": self._port_segment_size,
"first_port_name": self._first_port_name,
"custom_adapters": self._custom_adapters,
"ports": [port.__json__() for port in self.ports],
}
if topology_dump:
return topology
additional_data = {
"project_id": self._project.id,
"command_line": self._command_line,
"status": self._status,
"console_host": str(self._compute.console_host),
"node_directory": self._node_directory,
"ports": [port.__json__() for port in self.ports]
}
topology.update(additional_data)
return topology

View File

@ -28,6 +28,7 @@ class Notification:
"""
def __init__(self, controller):
self._controller = controller
self._project_listeners = {}
self._controller_listeners = set()
@ -71,19 +72,6 @@ class Notification:
:param event: Event to send
"""
# If use in tests for documentation we save a sample
if os.environ.get("PYTEST_BUILD_DOCUMENTATION") == "1":
os.makedirs("docs/api/notifications", exist_ok=True)
try:
import json
data = json.dumps(event, indent=4, sort_keys=True)
if "MagicMock" not in data:
with open(os.path.join("docs/api/notifications", action + ".json"), "w+") as f:
f.write(data)
except TypeError: # If we receive a mock as an event it will raise TypeError when using json dump
pass
for controller_listener in self._controller_listeners:
controller_listener.put_nowait((action, event, {}))
@ -127,19 +115,6 @@ class Notification:
:param event: Event to send
"""
# If use in tests for documentation we save a sample
if os.environ.get("PYTEST_BUILD_DOCUMENTATION") == "1":
os.makedirs("docs/api/notifications", exist_ok=True)
try:
import json
data = json.dumps(event, indent=4, sort_keys=True)
if "MagicMock" not in data:
with open(os.path.join("docs/api/notifications", action + ".json"), "w+") as f:
f.write(data)
except TypeError: # If we receive a mock as an event it will raise TypeError when using json dump
pass
if "project_id" in event or project_id:
self._send_event_to_project(event.get("project_id", project_id), action, event)
else:

View File

@ -633,7 +633,7 @@ class Project:
def _get_closed_data(self, section, id_key):
"""
Get the data for a project from the .gns3 when
the project is close
the project is closed
:param section: The section name in the .gns3
:param id_key: The key for the element unique id
@ -1117,7 +1117,7 @@ class Project:
try:
topo = project_to_topology(self)
path = self._topology_file()
log.debug("Write %s", path)
log.debug(f"Write topology file '{path}'")
with open(path + ".tmp", "w+", encoding="utf-8") as f:
json.dump(topo, f, indent=4, sort_keys=True)
shutil.move(path + ".tmp", path)
@ -1176,6 +1176,7 @@ class Project:
:param z: Z position
:returns: New node
"""
if node.status != "stopped" and not node.is_always_running():
raise ControllerError("Cannot duplicate node data while the node is running")

View File

@ -36,10 +36,6 @@ import logging
log = logging.getLogger(__name__)
# The string use to extract the date from the filename
FILENAME_TIME_FORMAT = "%d%m%y_%H%M%S"
class Snapshot:
"""
A snapshot object
@ -59,7 +55,7 @@ class Snapshot:
filename = (
self._name
+ "_"
+ datetime.utcfromtimestamp(self._created_at).replace(tzinfo=None).strftime(FILENAME_TIME_FORMAT)
+ datetime.utcfromtimestamp(self._created_at).replace(tzinfo=None).strftime("%d%m%y_%H%M%S")
+ ".gns3project"
)
else:
@ -67,7 +63,7 @@ class Snapshot:
datestring = filename.replace(self._name + "_", "").split(".")[0]
try:
self._created_at = (
datetime.strptime(datestring, FILENAME_TIME_FORMAT).replace(tzinfo=timezone.utc).timestamp()
datetime.strptime(datestring, "%d%m%y_%H%M%S").replace(tzinfo=timezone.utc).timestamp()
)
except ValueError:
self._created_at = datetime.utcnow().timestamp()

View File

@ -121,7 +121,8 @@ def load_topology(path):
"""
Open a topology file, patch it for last GNS3 release and return it
"""
log.debug("Read topology %s", path)
log.debug(f"Read topology {path}")
try:
with open(path, encoding="utf-8") as f:
topo = json.load(f)

View File

@ -20,7 +20,7 @@ from .common import ErrorMessage
from .version import Version
# Controller schemas
from .controller.links import Link
from .controller.links import LinkCreate, LinkUpdate, Link
from .controller.computes import ComputeCreate, ComputeUpdate, AutoIdlePC, Compute
from .controller.templates import TemplateCreate, TemplateUpdate, TemplateUsage, Template
from .controller.drawings import Drawing

View File

@ -17,7 +17,7 @@
from pydantic import BaseModel, Field
from typing import List, Optional
from enum import Enum
from uuid import UUID
from uuid import UUID, uuid4
from .labels import Label
@ -42,24 +42,45 @@ class LinkType(str, Enum):
serial = "serial"
class Link(BaseModel):
class LinkBase(BaseModel):
"""
Link data.
"""
link_id: Optional[UUID] = None
project_id: Optional[UUID] = None
nodes: Optional[List[LinkNode]] = None
nodes: Optional[List[LinkNode]] = Field(None, min_items=0, max_items=2)
suspend: Optional[bool] = None
filters: Optional[dict] = None
capturing: Optional[bool] = Field(None, description="Read only property. True if a capture running on the link")
class LinkCreate(LinkBase):
link_id: UUID = Field(default_factory=uuid4)
nodes: List[LinkNode] = Field(..., min_items=2, max_items=2)
class LinkUpdate(LinkBase):
pass
class Link(LinkBase):
link_id: UUID
project_id: Optional[UUID] = None
link_type: Optional[LinkType] = None
capturing: Optional[bool] = Field(
None,
description="Read only property. True if a capture running on the link"
)
capture_file_name: Optional[str] = Field(
None, description="Read only property. The name of the capture file if a capture is running"
None,
description="Read only property. The name of the capture file if a capture is running"
)
capture_file_path: Optional[str] = Field(
None, description="Read only property. The full path of the capture file if a capture is running"
None,
description="Read only property. The full path of the capture file if a capture is running"
)
capture_compute_id: Optional[str] = Field(
None, description="Read only property. The compute identifier where a capture is running"
None,
description="Read only property. The compute identifier where a capture is running"
)
link_type: Optional[LinkType] = None

View File

@ -20,7 +20,7 @@ import time
class CpuPercent:
"""
Ensures a minumum interval between two cpu_percent() calls
Ensures a minimum interval between two cpu_percent() calls
"""
_last_measurement = None # time of last measurement