Use black with -l 120 param.

This commit is contained in:
grossmj committed 2021-04-13 18:46:50 +09:30
1 parent f928738bd5
commit c021e21309
194 files changed
+6034 -4564

No files matched your search

+26 -10
View File
@@ -27,7 +27,7 @@ from gns3server.compute.compute_error import (
ComputeNotFoundError,
ComputeTimeoutError,
ComputeForbiddenError,
ComputeUnauthorizedError
ComputeUnauthorizedError,
)
from . import capabilities
@@ -50,9 +50,11 @@ from . import vmware_nodes
from . import vpcs_nodes
compute_api = FastAPI(title="GNS3 compute API",
description="This page describes the private compute API for GNS3. PLEASE DO NOT USE DIRECTLY!",
version="v3")
compute_api = FastAPI(
title="GNS3 compute API",
description="This page describes the private compute API for GNS3. PLEASE DO NOT USE DIRECTLY!",
version="v3",
)
@compute_api.exception_handler(ComputeError)
@@ -141,16 +143,30 @@ compute_api.include_router(compute.router, tags=["Compute"])
compute_api.include_router(notifications.router, tags=["Notifications"])
compute_api.include_router(projects.router, tags=["Projects"])
compute_api.include_router(images.router, tags=["Images"])
compute_api.include_router(atm_switch_nodes.router, prefix="/projects/{project_id}/atm_switch/nodes", tags=["ATM switch"])
compute_api.include_router(
atm_switch_nodes.router, prefix="/projects/{project_id}/atm_switch/nodes", tags=["ATM switch"]
)
compute_api.include_router(cloud_nodes.router, prefix="/projects/{project_id}/cloud/nodes", tags=["Cloud nodes"])
compute_api.include_router(docker_nodes.router, prefix="/projects/{project_id}/docker/nodes", tags=["Docker nodes"])
compute_api.include_router(dynamips_nodes.router, prefix="/projects/{project_id}/dynamips/nodes", tags=["Dynamips nodes"])
compute_api.include_router(ethernet_hub_nodes.router, prefix="/projects/{project_id}/ethernet_hub/nodes", tags=["Ethernet hub nodes"])
compute_api.include_router(ethernet_switch_nodes.router, prefix="/projects/{project_id}/ethernet_switch/nodes", tags=["Ethernet switch nodes"])
compute_api.include_router(frame_relay_switch_nodes.router, prefix="/projects/{project_id}/frame_relay_switch/nodes", tags=["Frame Relay switch nodes"])
compute_api.include_router(
dynamips_nodes.router, prefix="/projects/{project_id}/dynamips/nodes", tags=["Dynamips nodes"]
)
compute_api.include_router(
ethernet_hub_nodes.router, prefix="/projects/{project_id}/ethernet_hub/nodes", tags=["Ethernet hub nodes"]
)
compute_api.include_router(
ethernet_switch_nodes.router, prefix="/projects/{project_id}/ethernet_switch/nodes", tags=["Ethernet switch nodes"]
)
compute_api.include_router(
frame_relay_switch_nodes.router,
prefix="/projects/{project_id}/frame_relay_switch/nodes",
tags=["Frame Relay switch nodes"],
)
compute_api.include_router(iou_nodes.router, prefix="/projects/{project_id}/iou/nodes", tags=["IOU nodes"])
compute_api.include_router(nat_nodes.router, prefix="/projects/{project_id}/nat/nodes", tags=["NAT nodes"])
compute_api.include_router(qemu_nodes.router, prefix="/projects/{project_id}/qemu/nodes", tags=["Qemu nodes"])
compute_api.include_router(virtualbox_nodes.router, prefix="/projects/{project_id}/virtualbox/nodes", tags=["VirtualBox nodes"])
compute_api.include_router(
virtualbox_nodes.router, prefix="/projects/{project_id}/virtualbox/nodes", tags=["VirtualBox nodes"]
)
compute_api.include_router(vmware_nodes.router, prefix="/projects/{project_id}/vmware/nodes", tags=["VMware nodes"])
compute_api.include_router(vpcs_nodes.router, prefix="/projects/{project_id}/vpcs/nodes", tags=["VPCS nodes"])
@@ -29,9 +29,7 @@ from gns3server import schemas
from gns3server.compute.dynamips import Dynamips
from gns3server.compute.dynamips.nodes.atm_switch import ATMSwitch
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or ATM switch node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or ATM switch node"}}
router = APIRouter(responses=responses)
@@ -46,10 +44,12 @@ async def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.ATMSwitch,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create ATM switch node"}})
@router.post(
"",
response_model=schemas.ATMSwitch,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create ATM switch node"}},
)
async def create_atm_switch(project_id: UUID, node_data: schemas.ATMSwitchCreate):
"""
Create a new ATM switch node.
@@ -58,16 +58,17 @@ async def create_atm_switch(project_id: UUID, node_data: schemas.ATMSwitchCreate
# Use the Dynamips ATM switch to simulate this node
dynamips_manager = Dynamips.instance()
node_data = jsonable_encoder(node_data, exclude_unset=True)
node = await dynamips_manager.create_node(node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_type="atm_switch",
mappings=node_data.get("mappings"))
node = await dynamips_manager.create_node(
node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_type="atm_switch",
mappings=node_data.get("mappings"),
)
return node.__json__()
@router.get("/{node_id}",
response_model=schemas.ATMSwitch)
@router.get("/{node_id}", response_model=schemas.ATMSwitch)
def get_atm_switch(node: ATMSwitch = Depends(dep_node)):
"""
Return an ATM switch node.
@@ -76,9 +77,7 @@ def get_atm_switch(node: ATMSwitch = Depends(dep_node)):
return node.__json__()
@router.post("/{node_id}/duplicate",
response_model=schemas.ATMSwitch,
status_code=status.HTTP_201_CREATED)
@router.post("/{node_id}/duplicate", response_model=schemas.ATMSwitch, status_code=status.HTTP_201_CREATED)
async def duplicate_atm_switch(destination_node_id: UUID = Body(..., embed=True), node: ATMSwitch = Depends(dep_node)):
"""
Duplicate an ATM switch node.
@@ -88,8 +87,7 @@ async def duplicate_atm_switch(destination_node_id: UUID = Body(..., embed=True)
return new_node.__json__()
@router.put("/{node_id}",
response_model=schemas.ATMSwitch)
@router.put("/{node_id}", response_model=schemas.ATMSwitch)
async def update_atm_switch(node_data: schemas.ATMSwitchUpdate, node: ATMSwitch = Depends(dep_node)):
"""
Update an ATM switch node.
@@ -104,8 +102,7 @@ async def update_atm_switch(node_data: schemas.ATMSwitchUpdate, node: ATMSwitch
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_atm_switch_node(node: ATMSwitch = Depends(dep_node)):
"""
Delete an ATM switch node.
@@ -114,8 +111,7 @@ async def delete_atm_switch_node(node: ATMSwitch = Depends(dep_node)):
await Dynamips.instance().delete_node(node.id)
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
def start_atm_switch(node: ATMSwitch = Depends(dep_node)):
"""
Start an ATM switch node.
@@ -125,8 +121,7 @@ def start_atm_switch(node: ATMSwitch = Depends(dep_node)):
pass
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
def stop_atm_switch(node: ATMSwitch = Depends(dep_node)):
"""
Stop an ATM switch node.
@@ -136,8 +131,7 @@ def stop_atm_switch(node: ATMSwitch = Depends(dep_node)):
pass
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
def suspend_atm_switch(node: ATMSwitch = Depends(dep_node)):
"""
Suspend an ATM switch node.
@@ -147,13 +141,14 @@ def suspend_atm_switch(node: ATMSwitch = Depends(dep_node)):
pass
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def create_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO,
node: ATMSwitch = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def create_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: ATMSwitch = Depends(dep_node)
):
"""
Add a NIO (Network Input/Output) to the node.
The adapter number on the switch is always 0.
@@ -164,8 +159,7 @@ async def create_nio(adapter_number: int,
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_nio(adapter_number: int, port_number: int, node: ATMSwitch = Depends(dep_node)):
"""
Remove a NIO (Network Input/Output) from the node.
@@ -177,10 +171,9 @@ async def delete_nio(adapter_number: int, port_number: int, node: ATMSwitch = De
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: ATMSwitch = Depends(dep_node)):
async def start_capture(
adapter_number: int, port_number: int, node_capture_data: schemas.NodeCapture, node: ATMSwitch = Depends(dep_node)
):
"""
Start a packet capture on the node.
The adapter number on the switch is always 0.
@@ -191,8 +184,10 @@ async def start_capture(adapter_number: int,
return {"pcap_file_path": pcap_file_path}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop_capture",
status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop_capture",
status_code=status.HTTP_204_NO_CONTENT,
)
async def stop_capture(adapter_number: int, port_number: int, node: ATMSwitch = Depends(dep_node)):
"""
Stop a packet capture on the node.
@@ -31,18 +31,18 @@ from gns3server import schemas
router = APIRouter()
@router.get("/capabilities",
response_model=schemas.Capabilities
)
@router.get("/capabilities", response_model=schemas.Capabilities)
def get_capabilities():
node_types = []
for module in MODULES:
node_types.extend(module.node_types())
return {"version": __version__,
"platform": sys.platform,
"cpus": psutil.cpu_count(logical=True),
"memory": psutil.virtual_memory().total,
"disk_size": psutil.disk_usage(get_default_project_directory()).total,
"node_types": node_types}
return {
"version": __version__,
"platform": sys.platform,
"cpus": psutil.cpu_count(logical=True),
"memory": psutil.virtual_memory().total,
"disk_size": psutil.disk_usage(get_default_project_directory()).total,
"node_types": node_types,
}
+49 -46
View File
@@ -30,9 +30,7 @@ from gns3server import schemas
from gns3server.compute.builtin import Builtin
from gns3server.compute.builtin.nodes.cloud import Cloud
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or cloud node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or cloud node"}}
router = APIRouter(responses=responses)
@@ -47,10 +45,12 @@ def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.Cloud,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create cloud node"}})
@router.post(
"",
response_model=schemas.Cloud,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create cloud node"}},
)
async def create_cloud(project_id: UUID, node_data: schemas.CloudCreate):
"""
Create a new cloud node.
@@ -58,11 +58,13 @@ async def create_cloud(project_id: UUID, node_data: schemas.CloudCreate):
builtin_manager = Builtin.instance()
node_data = jsonable_encoder(node_data, exclude_unset=True)
node = await builtin_manager.create_node(node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_type="cloud",
ports=node_data.get("ports_mapping"))
node = await builtin_manager.create_node(
node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_type="cloud",
ports=node_data.get("ports_mapping"),
)
# add the remote console settings
node.remote_console_host = node_data.get("remote_console_host", node.remote_console_host)
@@ -73,8 +75,7 @@ async def create_cloud(project_id: UUID, node_data: schemas.CloudCreate):
return node.__json__()
@router.get("/{node_id}",
response_model=schemas.Cloud)
@router.get("/{node_id}", response_model=schemas.Cloud)
def get_cloud(node: Cloud = Depends(dep_node)):
"""
Return a cloud node.
@@ -83,8 +84,7 @@ def get_cloud(node: Cloud = Depends(dep_node)):
return node.__json__()
@router.put("/{node_id}",
response_model=schemas.Cloud)
@router.put("/{node_id}", response_model=schemas.Cloud)
def update_cloud(node_data: schemas.CloudUpdate, node: Cloud = Depends(dep_node)):
"""
Update a cloud node.
@@ -98,8 +98,7 @@ def update_cloud(node_data: schemas.CloudUpdate, node: Cloud = Depends(dep_node)
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_cloud(node: Cloud = Depends(dep_node)):
"""
Delete a cloud node.
@@ -108,8 +107,7 @@ async def delete_cloud(node: Cloud = Depends(dep_node)):
await Builtin.instance().delete_node(node.id)
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_cloud(node: Cloud = Depends(dep_node)):
"""
Start a cloud node.
@@ -118,8 +116,7 @@ async def start_cloud(node: Cloud = Depends(dep_node)):
await node.start()
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_cloud(node: Cloud = Depends(dep_node)):
"""
Stop a cloud node.
@@ -129,8 +126,7 @@ async def stop_cloud(node: Cloud = Depends(dep_node)):
pass
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_cloud(node: Cloud = Depends(dep_node)):
"""
Suspend a cloud node.
@@ -140,13 +136,17 @@ async def suspend_cloud(node: Cloud = Depends(dep_node)):
pass
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO])
async def create_cloud_nio(adapter_number: int,
port_number: int,
nio_data: Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
node: Cloud = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
)
async def create_cloud_nio(
adapter_number: int,
port_number: int,
nio_data: Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
node: Cloud = Depends(dep_node),
):
"""
Add a NIO (Network Input/Output) to the node.
The adapter number on the cloud is always 0.
@@ -157,13 +157,17 @@ async def create_cloud_nio(adapter_number: int,
return nio.__json__()
@router.put("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO])
async def update_cloud_nio(adapter_number: int,
port_number: int,
nio_data: Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
node: Cloud = Depends(dep_node)):
@router.put(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
)
async def update_cloud_nio(
adapter_number: int,
port_number: int,
nio_data: Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
node: Cloud = Depends(dep_node),
):
"""
Update a NIO (Network Input/Output) to the node.
The adapter number on the cloud is always 0.
@@ -176,8 +180,7 @@ async def update_cloud_nio(adapter_number: int,
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_cloud_nio(adapter_number: int, port_number: int, node: Cloud = Depends(dep_node)):
"""
Remove a NIO (Network Input/Output) from the node.
@@ -188,10 +191,9 @@ async def delete_cloud_nio(adapter_number: int, port_number: int, node: Cloud =
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_cloud_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: Cloud = Depends(dep_node)):
async def start_cloud_capture(
adapter_number: int, port_number: int, node_capture_data: schemas.NodeCapture, node: Cloud = Depends(dep_node)
):
"""
Start a packet capture on the node.
The adapter number on the cloud is always 0.
@@ -202,8 +204,9 @@ async def start_cloud_capture(adapter_number: int,
return {"pcap_file_path": pcap_file_path}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT
)
async def stop_cloud_capture(adapter_number: int, port_number: int, node: Cloud = Depends(dep_node)):
"""
Stop a packet capture on the node.
+30 -26
View File
@@ -42,8 +42,7 @@ from typing import Optional, List
router = APIRouter()
@router.post("/projects/{project_id}/ports/udp",
status_code=status.HTTP_201_CREATED)
@router.post("/projects/{project_id}/ports/udp", status_code=status.HTTP_201_CREATED)
def allocate_udp_port(project_id: UUID) -> dict:
"""
Allocate an UDP port on the compute.
@@ -106,19 +105,21 @@ def compute_statistics() -> dict:
disk_usage_percent = int(psutil.disk_usage(get_default_project_directory()).percent)
except psutil.Error as e:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
#raise HTTPConflict(text="Psutil error detected: {}".format(e))
# raise HTTPConflict(text="Psutil error detected: {}".format(e))
return {"memory_total": memory_total,
"memory_free": memory_free,
"memory_used": memory_used,
"swap_total": swap_total,
"swap_free": swap_free,
"swap_used": swap_used,
"cpu_usage_percent": cpu_percent,
"memory_usage_percent": memory_percent,
"swap_usage_percent": swap_percent,
"disk_usage_percent": disk_usage_percent,
"load_average_percent": load_average_percent}
return {
"memory_total": memory_total,
"memory_free": memory_free,
"memory_used": memory_used,
"swap_total": swap_total,
"swap_free": swap_free,
"swap_used": swap_used,
"cpu_usage_percent": cpu_percent,
"memory_usage_percent": memory_percent,
"swap_usage_percent": swap_percent,
"disk_usage_percent": disk_usage_percent,
"load_average_percent": load_average_percent,
}
@router.get("/qemu/binaries")
@@ -142,9 +143,11 @@ async def get_qemu_capabilities() -> dict:
return capabilities
@router.post("/qemu/img",
status_code=status.HTTP_204_NO_CONTENT,
responses={403: {"model": schemas.ErrorMessage, "description": "Forbidden to create Qemu image"}})
@router.post(
"/qemu/img",
status_code=status.HTTP_204_NO_CONTENT,
responses={403: {"model": schemas.ErrorMessage, "description": "Forbidden to create Qemu image"}},
)
async def create_qemu_image(image_data: schemas.QemuImageCreate):
"""
Create a Qemu image.
@@ -154,12 +157,16 @@ async def create_qemu_image(image_data: schemas.QemuImageCreate):
if Config.instance().settings.Server.local is False:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
await Qemu.instance().create_disk(image_data.qemu_img, image_data.path, jsonable_encoder(image_data, exclude_unset=True))
await Qemu.instance().create_disk(
image_data.qemu_img, image_data.path, jsonable_encoder(image_data, exclude_unset=True)
)
@router.put("/qemu/img",
status_code=status.HTTP_204_NO_CONTENT,
responses={403: {"model": schemas.ErrorMessage, "description": "Forbidden to update Qemu image"}})
@router.put(
"/qemu/img",
status_code=status.HTTP_204_NO_CONTENT,
responses={403: {"model": schemas.ErrorMessage, "description": "Forbidden to update Qemu image"}},
)
async def update_qemu_image(image_data: schemas.QemuImageUpdate):
"""
Update a Qemu image.
@@ -173,17 +180,14 @@ async def update_qemu_image(image_data: schemas.QemuImageUpdate):
await Qemu.instance().resize_disk(image_data.qemu_img, image_data.path, image_data.extend)
@router.get("/virtualbox/vms",
response_model=List[dict])
@router.get("/virtualbox/vms", response_model=List[dict])
async def get_virtualbox_vms():
vbox_manager = VirtualBox.instance()
return await vbox_manager.list_vms()
@router.get("/vmware/vms",
response_model=List[dict])
@router.get("/vmware/vms", response_model=List[dict])
async def get_vms():
vmware_manager = VMware.instance()
return await vmware_manager.list_vms()
+76 -73
View File
@@ -29,9 +29,7 @@ from gns3server import schemas
from gns3server.compute.docker import Docker
from gns3server.compute.docker.docker_vm import DockerVM
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or Docker node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or Docker node"}}
router = APIRouter(responses=responses)
@@ -46,10 +44,12 @@ def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.Docker,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create Docker node"}})
@router.post(
"",
response_model=schemas.Docker,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create Docker node"}},
)
async def create_docker_node(project_id: UUID, node_data: schemas.DockerCreate):
"""
Create a new Docker node.
@@ -57,24 +57,26 @@ async def create_docker_node(project_id: UUID, node_data: schemas.DockerCreate):
docker_manager = Docker.instance()
node_data = jsonable_encoder(node_data, exclude_unset=True)
container = await docker_manager.create_node(node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
image=node_data.pop("image"),
start_command=node_data.get("start_command"),
environment=node_data.get("environment"),
adapters=node_data.get("adapters"),
console=node_data.get("console"),
console_type=node_data.get("console_type"),
console_resolution=node_data.get("console_resolution", "1024x768"),
console_http_port=node_data.get("console_http_port", 80),
console_http_path=node_data.get("console_http_path", "/"),
aux=node_data.get("aux"),
aux_type=node_data.pop("aux_type", "none"),
extra_hosts=node_data.get("extra_hosts"),
extra_volumes=node_data.get("extra_volumes"),
memory=node_data.get("memory", 0),
cpus=node_data.get("cpus", 0))
container = await docker_manager.create_node(
node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
image=node_data.pop("image"),
start_command=node_data.get("start_command"),
environment=node_data.get("environment"),
adapters=node_data.get("adapters"),
console=node_data.get("console"),
console_type=node_data.get("console_type"),
console_resolution=node_data.get("console_resolution", "1024x768"),
console_http_port=node_data.get("console_http_port", 80),
console_http_path=node_data.get("console_http_path", "/"),
aux=node_data.get("aux"),
aux_type=node_data.pop("aux_type", "none"),
extra_hosts=node_data.get("extra_hosts"),
extra_volumes=node_data.get("extra_volumes"),
memory=node_data.get("memory", 0),
cpus=node_data.get("cpus", 0),
)
for name, value in node_data.items():
if name != "node_id":
if hasattr(container, name) and getattr(container, name) != value:
@@ -83,8 +85,7 @@ async def create_docker_node(project_id: UUID, node_data: schemas.DockerCreate):
return container.__json__()
@router.get("/{node_id}",
response_model=schemas.Docker)
@router.get("/{node_id}", response_model=schemas.Docker)
def get_docker_node(node: DockerVM = Depends(dep_node)):
"""
Return a Docker node.
@@ -93,18 +94,28 @@ def get_docker_node(node: DockerVM = Depends(dep_node)):
return node.__json__()
@router.put("/{node_id}",
response_model=schemas.Docker)
@router.put("/{node_id}", response_model=schemas.Docker)
async def update_docker_node(node_data: schemas.DockerUpdate, node: DockerVM = Depends(dep_node)):
"""
Update a Docker node.
"""
props = [
"name", "console", "console_type", "aux", "aux_type", "console_resolution",
"console_http_port", "console_http_path", "start_command",
"environment", "adapters", "extra_hosts", "extra_volumes",
"memory", "cpus"
"name",
"console",
"console_type",
"aux",
"aux_type",
"console_resolution",
"console_http_port",
"console_http_path",
"start_command",
"environment",
"adapters",
"extra_hosts",
"extra_volumes",
"memory",
"cpus",
]
changed = False
@@ -120,8 +131,7 @@ async def update_docker_node(node_data: schemas.DockerUpdate, node: DockerVM = D
return node.__json__()
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_docker_node(node: DockerVM = Depends(dep_node)):
"""
Start a Docker node.
@@ -130,8 +140,7 @@ async def start_docker_node(node: DockerVM = Depends(dep_node)):
await node.start()
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_docker_node(node: DockerVM = Depends(dep_node)):
"""
Stop a Docker node.
@@ -140,8 +149,7 @@ async def stop_docker_node(node: DockerVM = Depends(dep_node)):
await node.stop()
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_docker_node(node: DockerVM = Depends(dep_node)):
"""
Suspend a Docker node.
@@ -150,8 +158,7 @@ async def suspend_docker_node(node: DockerVM = Depends(dep_node)):
await node.pause()
@router.post("/{node_id}/reload",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_docker_node(node: DockerVM = Depends(dep_node)):
"""
Reload a Docker node.
@@ -160,8 +167,7 @@ async def reload_docker_node(node: DockerVM = Depends(dep_node)):
await node.restart()
@router.post("/{node_id}/pause",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/pause", status_code=status.HTTP_204_NO_CONTENT)
async def pause_docker_node(node: DockerVM = Depends(dep_node)):
"""
Pause a Docker node.
@@ -170,8 +176,7 @@ async def pause_docker_node(node: DockerVM = Depends(dep_node)):
await node.pause()
@router.post("/{node_id}/unpause",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/unpause", status_code=status.HTTP_204_NO_CONTENT)
async def unpause_docker_node(node: DockerVM = Depends(dep_node)):
"""
Unpause a Docker node.
@@ -180,8 +185,7 @@ async def unpause_docker_node(node: DockerVM = Depends(dep_node)):
await node.unpause()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_docker_node(node: DockerVM = Depends(dep_node)):
"""
Delete a Docker node.
@@ -190,9 +194,7 @@ async def delete_docker_node(node: DockerVM = Depends(dep_node)):
await node.delete()
@router.post("/{node_id}/duplicate",
response_model=schemas.Docker,
status_code=status.HTTP_201_CREATED)
@router.post("/{node_id}/duplicate", response_model=schemas.Docker, status_code=status.HTTP_201_CREATED)
async def duplicate_docker_node(destination_node_id: UUID = Body(..., embed=True), node: DockerVM = Depends(dep_node)):
"""
Duplicate a Docker node.
@@ -202,13 +204,14 @@ async def duplicate_docker_node(destination_node_id: UUID = Body(..., embed=True
return new_node.__json__()
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def create_docker_node_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO,
node: DockerVM = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def create_docker_node_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: DockerVM = Depends(dep_node)
):
"""
Add a NIO (Network Input/Output) to the node.
The port number on the Docker node is always 0.
@@ -219,12 +222,14 @@ async def create_docker_node_nio(adapter_number: int,
return nio.__json__()
@router.put("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def update_docker_node_nio(adapter_number: int,
port_number: int, nio_data: schemas.UDPNIO,
node: DockerVM = Depends(dep_node)):
@router.put(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def update_docker_node_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: DockerVM = Depends(dep_node)
):
"""
Update a NIO (Network Input/Output) on the node.
The port number on the Docker node is always 0.
@@ -237,8 +242,7 @@ async def update_docker_node_nio(adapter_number: int,
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_docker_node_nio(adapter_number: int, port_number: int, node: DockerVM = Depends(dep_node)):
"""
Delete a NIO (Network Input/Output) from the node.
@@ -249,10 +253,9 @@ async def delete_docker_node_nio(adapter_number: int, port_number: int, node: Do
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_docker_node_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: DockerVM = Depends(dep_node)):
async def start_docker_node_capture(
adapter_number: int, port_number: int, node_capture_data: schemas.NodeCapture, node: DockerVM = Depends(dep_node)
):
"""
Start a packet capture on the node.
The port number on the Docker node is always 0.
@@ -263,8 +266,9 @@ async def start_docker_node_capture(adapter_number: int,
return {"pcap_file_path": str(pcap_file_path)}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT
)
async def stop_docker_node_capture(adapter_number: int, port_number: int, node: DockerVM = Depends(dep_node)):
"""
Stop a packet capture on the node.
@@ -295,8 +299,7 @@ async def console_ws(websocket: WebSocket, node: DockerVM = Depends(dep_node)):
await node.start_websocket_console(websocket)
@router.post("/{node_id}/console/reset",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: DockerVM = Depends(dep_node)):
await node.reset_console()
+53 -61
View File
@@ -32,19 +32,12 @@ from gns3server.compute.dynamips.nodes.router import Router
from gns3server.compute.dynamips.dynamips_error import DynamipsError
from gns3server import schemas
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or Dynamips node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or Dynamips node"}}
router = APIRouter(responses=responses)
DEFAULT_CHASSIS = {
"c1700": "1720",
"c2600": "2610",
"c3600": "3640"
}
DEFAULT_CHASSIS = {"c1700": "1720", "c2600": "2610", "c3600": "3640"}
def dep_node(project_id: UUID, node_id: UUID):
@@ -57,10 +50,12 @@ def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.Dynamips,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create Dynamips node"}})
@router.post(
"",
response_model=schemas.Dynamips,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create Dynamips node"}},
)
async def create_router(project_id: UUID, node_data: schemas.DynamipsCreate):
"""
Create a new Dynamips router.
@@ -72,23 +67,24 @@ async def create_router(project_id: UUID, node_data: schemas.DynamipsCreate):
if not node_data.chassis and platform in DEFAULT_CHASSIS:
chassis = DEFAULT_CHASSIS[platform]
node_data = jsonable_encoder(node_data, exclude_unset=True)
vm = await dynamips_manager.create_node(node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
dynamips_id=node_data.get("dynamips_id"),
platform=platform,
console=node_data.get("console"),
console_type=node_data.get("console_type", "telnet"),
aux=node_data.get("aux"),
aux_type=node_data.pop("aux_type", "none"),
chassis=chassis,
node_type="dynamips")
vm = await dynamips_manager.create_node(
node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
dynamips_id=node_data.get("dynamips_id"),
platform=platform,
console=node_data.get("console"),
console_type=node_data.get("console_type", "telnet"),
aux=node_data.get("aux"),
aux_type=node_data.pop("aux_type", "none"),
chassis=chassis,
node_type="dynamips",
)
await dynamips_manager.update_vm_settings(vm, node_data)
return vm.__json__()
@router.get("/{node_id}",
response_model=schemas.Dynamips)
@router.get("/{node_id}", response_model=schemas.Dynamips)
def get_router(node: Router = Depends(dep_node)):
"""
Return Dynamips router.
@@ -97,8 +93,7 @@ def get_router(node: Router = Depends(dep_node)):
return node.__json__()
@router.put("/{node_id}",
response_model=schemas.Dynamips)
@router.put("/{node_id}", response_model=schemas.Dynamips)
async def update_router(node_data: schemas.DynamipsUpdate, node: Router = Depends(dep_node)):
"""
Update a Dynamips router.
@@ -109,8 +104,7 @@ async def update_router(node_data: schemas.DynamipsUpdate, node: Router = Depend
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_router(node: Router = Depends(dep_node)):
"""
Delete a Dynamips router.
@@ -119,8 +113,7 @@ async def delete_router(node: Router = Depends(dep_node)):
await Dynamips.instance().delete_node(node.id)
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_router(node: Router = Depends(dep_node)):
"""
Start a Dynamips router.
@@ -133,8 +126,7 @@ async def start_router(node: Router = Depends(dep_node)):
await node.start()
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_router(node: Router = Depends(dep_node)):
"""
Stop a Dynamips router.
@@ -143,15 +135,13 @@ async def stop_router(node: Router = Depends(dep_node)):
await node.stop()
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_router(node: Router = Depends(dep_node)):
await node.suspend()
@router.post("/{node_id}/resume",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/resume", status_code=status.HTTP_204_NO_CONTENT)
async def resume_router(node: Router = Depends(dep_node)):
"""
Resume a suspended Dynamips router.
@@ -160,8 +150,7 @@ async def resume_router(node: Router = Depends(dep_node)):
await node.resume()
@router.post("/{node_id}/reload",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_router(node: Router = Depends(dep_node)):
"""
Reload a suspended Dynamips router.
@@ -170,9 +159,11 @@ async def reload_router(node: Router = Depends(dep_node)):
await node.reload()
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def create_nio(adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: Router = Depends(dep_node)):
"""
Add a NIO (Network Input/Output) to the node.
@@ -183,9 +174,11 @@ async def create_nio(adapter_number: int, port_number: int, nio_data: schemas.UD
return nio.__json__()
@router.put("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
@router.put(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def update_nio(adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: Router = Depends(dep_node)):
"""
Update a NIO (Network Input/Output) on the node.
@@ -198,8 +191,7 @@ async def update_nio(adapter_number: int, port_number: int, nio_data: schemas.UD
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_nio(adapter_number: int, port_number: int, node: Router = Depends(dep_node)):
"""
Delete a NIO (Network Input/Output) from the node.
@@ -210,29 +202,31 @@ async def delete_nio(adapter_number: int, port_number: int, node: Router = Depen
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: Router = Depends(dep_node)):
async def start_capture(
adapter_number: int, port_number: int, node_capture_data: schemas.NodeCapture, node: Router = Depends(dep_node)
):
"""
Start a packet capture on the node.
"""
pcap_file_path = os.path.join(node.project.capture_working_directory(), node_capture_data.capture_file_name)
if sys.platform.startswith('win'):
if sys.platform.startswith("win"):
# FIXME: Dynamips (Cygwin actually) doesn't like non ascii paths on Windows
try:
pcap_file_path.encode('ascii')
pcap_file_path.encode("ascii")
except UnicodeEncodeError:
raise DynamipsError(f"The capture file path '{pcap_file_path}' must only contain ASCII (English) characters")
raise DynamipsError(
f"The capture file path '{pcap_file_path}' must only contain ASCII (English) characters"
)
await node.start_capture(adapter_number, port_number, pcap_file_path, node_capture_data.data_link_type)
return {"pcap_file_path": pcap_file_path}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT
)
async def stop_capture(adapter_number: int, port_number: int, node: Router = Depends(dep_node)):
"""
Stop a packet capture on the node.
@@ -272,8 +266,7 @@ async def get_auto_idlepc(node: Router = Depends(dep_node)) -> dict:
return {"idlepc": idlepc}
@router.post("/{node_id}/duplicate",
status_code=status.HTTP_201_CREATED)
@router.post("/{node_id}/duplicate", status_code=status.HTTP_201_CREATED)
async def duplicate_router(destination_node_id: UUID, node: Router = Depends(dep_node)):
"""
Duplicate a router.
@@ -292,8 +285,7 @@ async def console_ws(websocket: WebSocket, node: Router = Depends(dep_node)):
await node.start_websocket_console(websocket)
@router.post("/{node_id}/console/reset",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: Router = Depends(dep_node)):
await node.reset_console()
@@ -29,9 +29,7 @@ from gns3server.compute.dynamips import Dynamips
from gns3server.compute.dynamips.nodes.ethernet_hub import EthernetHub
from gns3server import schemas
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or Ethernet hub node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or Ethernet hub node"}}
router = APIRouter(responses=responses)
@@ -46,10 +44,12 @@ def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.EthernetHub,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create Ethernet hub node"}})
@router.post(
"",
response_model=schemas.EthernetHub,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create Ethernet hub node"}},
)
async def create_ethernet_hub(project_id: UUID, node_data: schemas.EthernetHubCreate):
"""
Create a new Ethernet hub.
@@ -58,16 +58,17 @@ async def create_ethernet_hub(project_id: UUID, node_data: schemas.EthernetHubCr
# Use the Dynamips Ethernet hub to simulate this node
dynamips_manager = Dynamips.instance()
node_data = jsonable_encoder(node_data, exclude_unset=True)
node = await dynamips_manager.create_node(node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_type="ethernet_hub",
ports=node_data.get("ports_mapping"))
node = await dynamips_manager.create_node(
node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_type="ethernet_hub",
ports=node_data.get("ports_mapping"),
)
return node.__json__()
@router.get("/{node_id}",
response_model=schemas.EthernetHub)
@router.get("/{node_id}", response_model=schemas.EthernetHub)
def get_ethernet_hub(node: EthernetHub = Depends(dep_node)):
"""
Return an Ethernet hub.
@@ -76,11 +77,10 @@ def get_ethernet_hub(node: EthernetHub = Depends(dep_node)):
return node.__json__()
@router.post("/{node_id}/duplicate",
response_model=schemas.EthernetHub,
status_code=status.HTTP_201_CREATED)
async def duplicate_ethernet_hub(destination_node_id: UUID = Body(..., embed=True),
node: EthernetHub = Depends(dep_node)):
@router.post("/{node_id}/duplicate", response_model=schemas.EthernetHub, status_code=status.HTTP_201_CREATED)
async def duplicate_ethernet_hub(
destination_node_id: UUID = Body(..., embed=True), node: EthernetHub = Depends(dep_node)
):
"""
Duplicate an Ethernet hub.
"""
@@ -89,8 +89,7 @@ async def duplicate_ethernet_hub(destination_node_id: UUID = Body(..., embed=Tru
return new_node.__json__()
@router.put("/{node_id}",
response_model=schemas.EthernetHub)
@router.put("/{node_id}", response_model=schemas.EthernetHub)
async def update_ethernet_hub(node_data: schemas.EthernetHubUpdate, node: EthernetHub = Depends(dep_node)):
"""
Update an Ethernet hub.
@@ -105,8 +104,7 @@ async def update_ethernet_hub(node_data: schemas.EthernetHubUpdate, node: Ethern
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_ethernet_hub(node: EthernetHub = Depends(dep_node)):
"""
Delete an Ethernet hub.
@@ -115,8 +113,7 @@ async def delete_ethernet_hub(node: EthernetHub = Depends(dep_node)):
await Dynamips.instance().delete_node(node.id)
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
def start_ethernet_hub(node: EthernetHub = Depends(dep_node)):
"""
Start an Ethernet hub.
@@ -126,8 +123,7 @@ def start_ethernet_hub(node: EthernetHub = Depends(dep_node)):
pass
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
def stop_ethernet_hub(node: EthernetHub = Depends(dep_node)):
"""
Stop an Ethernet hub.
@@ -137,8 +133,7 @@ def stop_ethernet_hub(node: EthernetHub = Depends(dep_node)):
pass
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
def suspend_ethernet_hub(node: EthernetHub = Depends(dep_node)):
"""
Suspend an Ethernet hub.
@@ -148,13 +143,14 @@ def suspend_ethernet_hub(node: EthernetHub = Depends(dep_node)):
pass
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def create_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO,
node: EthernetHub = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def create_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: EthernetHub = Depends(dep_node)
):
"""
Add a NIO (Network Input/Output) to the node.
The adapter number on the hub is always 0.
@@ -165,8 +161,7 @@ async def create_nio(adapter_number: int,
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_nio(adapter_number: int, port_number: int, node: EthernetHub = Depends(dep_node)):
"""
Delete a NIO (Network Input/Output) from the node.
@@ -178,10 +173,9 @@ async def delete_nio(adapter_number: int, port_number: int, node: EthernetHub =
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: EthernetHub = Depends(dep_node)):
async def start_capture(
adapter_number: int, port_number: int, node_capture_data: schemas.NodeCapture, node: EthernetHub = Depends(dep_node)
):
"""
Start a packet capture on the node.
The adapter number on the hub is always 0.
@@ -192,8 +186,9 @@ async def start_capture(adapter_number: int,
return {"pcap_file_path": pcap_file_path}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT
)
async def stop_capture(adapter_number: int, port_number: int, node: EthernetHub = Depends(dep_node)):
"""
Stop a packet capture on the node.
@@ -29,9 +29,7 @@ from gns3server.compute.dynamips import Dynamips
from gns3server.compute.dynamips.nodes.ethernet_switch import EthernetSwitch
from gns3server import schemas
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or Ethernet switch node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or Ethernet switch node"}}
router = APIRouter(responses=responses)
@@ -46,10 +44,12 @@ def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.EthernetSwitch,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create Ethernet switch node"}})
@router.post(
"",
response_model=schemas.EthernetSwitch,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create Ethernet switch node"}},
)
async def create_ethernet_switch(project_id: UUID, node_data: schemas.EthernetSwitchCreate):
"""
Create a new Ethernet switch.
@@ -58,29 +58,29 @@ async def create_ethernet_switch(project_id: UUID, node_data: schemas.EthernetSw
# Use the Dynamips Ethernet switch to simulate this node
dynamips_manager = Dynamips.instance()
node_data = jsonable_encoder(node_data, exclude_unset=True)
node = await dynamips_manager.create_node(node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
console=node_data.get("console"),
console_type=node_data.get("console_type"),
node_type="ethernet_switch",
ports=node_data.get("ports_mapping"))
node = await dynamips_manager.create_node(
node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
console=node_data.get("console"),
console_type=node_data.get("console_type"),
node_type="ethernet_switch",
ports=node_data.get("ports_mapping"),
)
return node.__json__()
@router.get("/{node_id}",
response_model=schemas.EthernetSwitch)
@router.get("/{node_id}", response_model=schemas.EthernetSwitch)
def get_ethernet_switch(node: EthernetSwitch = Depends(dep_node)):
return node.__json__()
@router.post("/{node_id}/duplicate",
response_model=schemas.EthernetSwitch,
status_code=status.HTTP_201_CREATED)
async def duplicate_ethernet_switch(destination_node_id: UUID = Body(..., embed=True),
node: EthernetSwitch = Depends(dep_node)):
@router.post("/{node_id}/duplicate", response_model=schemas.EthernetSwitch, status_code=status.HTTP_201_CREATED)
async def duplicate_ethernet_switch(
destination_node_id: UUID = Body(..., embed=True), node: EthernetSwitch = Depends(dep_node)
):
"""
Duplicate an Ethernet switch.
"""
@@ -89,8 +89,7 @@ async def duplicate_ethernet_switch(destination_node_id: UUID = Body(..., embed=
return new_node.__json__()
@router.put("/{node_id}",
response_model=schemas.EthernetSwitch)
@router.put("/{node_id}", response_model=schemas.EthernetSwitch)
async def update_ethernet_switch(node_data: schemas.EthernetSwitchUpdate, node: EthernetSwitch = Depends(dep_node)):
"""
Update an Ethernet switch.
@@ -108,8 +107,7 @@ async def update_ethernet_switch(node_data: schemas.EthernetSwitchUpdate, node:
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_ethernet_switch(node: EthernetSwitch = Depends(dep_node)):
"""
Delete an Ethernet switch.
@@ -118,8 +116,7 @@ async def delete_ethernet_switch(node: EthernetSwitch = Depends(dep_node)):
await Dynamips.instance().delete_node(node.id)
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
def start_ethernet_switch(node: EthernetSwitch = Depends(dep_node)):
"""
Start an Ethernet switch.
@@ -129,8 +126,7 @@ def start_ethernet_switch(node: EthernetSwitch = Depends(dep_node)):
pass
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
def stop_ethernet_switch(node: EthernetSwitch = Depends(dep_node)):
"""
Stop an Ethernet switch.
@@ -140,8 +136,7 @@ def stop_ethernet_switch(node: EthernetSwitch = Depends(dep_node)):
pass
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
def suspend_ethernet_switch(node: EthernetSwitch = Depends(dep_node)):
"""
Suspend an Ethernet switch.
@@ -151,21 +146,21 @@ def suspend_ethernet_switch(node: EthernetSwitch = Depends(dep_node)):
pass
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def create_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO,
node: EthernetSwitch = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def create_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: EthernetSwitch = Depends(dep_node)
):
nio = await Dynamips.instance().create_nio(node, jsonable_encoder(nio_data, exclude_unset=True))
await node.add_nio(nio, port_number)
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_nio(adapter_number: int, port_number: int, node: EthernetSwitch = Depends(dep_node)):
"""
Delete a NIO (Network Input/Output) from the node.
@@ -177,10 +172,12 @@ async def delete_nio(adapter_number: int, port_number: int, node: EthernetSwitch
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: EthernetSwitch = Depends(dep_node)):
async def start_capture(
adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: EthernetSwitch = Depends(dep_node),
):
"""
Start a packet capture on the node.
The adapter number on the switch is always 0.
@@ -191,9 +188,10 @@ async def start_capture(adapter_number: int,
return {"pcap_file_path": pcap_file_path}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
async def stop_capture(adapter_number: int,port_number: int, node: EthernetSwitch = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT
)
async def stop_capture(adapter_number: int, port_number: int, node: EthernetSwitch = Depends(dep_node)):
"""
Stop a packet capture on the node.
The adapter number on the switch is always 0.
@@ -29,9 +29,7 @@ from gns3server import schemas
from gns3server.compute.dynamips import Dynamips
from gns3server.compute.dynamips.nodes.frame_relay_switch import FrameRelaySwitch
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or Frame Relay switch node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or Frame Relay switch node"}}
router = APIRouter(responses=responses)
@@ -46,10 +44,12 @@ def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.FrameRelaySwitch,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create Frame Relay switch node"}})
@router.post(
"",
response_model=schemas.FrameRelaySwitch,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create Frame Relay switch node"}},
)
async def create_frame_relay_switch(project_id: UUID, node_data: schemas.FrameRelaySwitchCreate):
"""
Create a new Frame Relay switch node.
@@ -58,16 +58,17 @@ async def create_frame_relay_switch(project_id: UUID, node_data: schemas.FrameRe
# Use the Dynamips Frame Relay switch to simulate this node
dynamips_manager = Dynamips.instance()
node_data = jsonable_encoder(node_data, exclude_unset=True)
node = await dynamips_manager.create_node(node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_type="frame_relay_switch",
mappings=node_data.get("mappings"))
node = await dynamips_manager.create_node(
node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_type="frame_relay_switch",
mappings=node_data.get("mappings"),
)
return node.__json__()
@router.get("/{node_id}",
response_model=schemas.FrameRelaySwitch)
@router.get("/{node_id}", response_model=schemas.FrameRelaySwitch)
def get_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)):
"""
Return a Frame Relay switch node.
@@ -76,11 +77,10 @@ def get_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)):
return node.__json__()
@router.post("/{node_id}/duplicate",
response_model=schemas.FrameRelaySwitch,
status_code=status.HTTP_201_CREATED)
async def duplicate_frame_relay_switch(destination_node_id: UUID = Body(..., embed=True),
node: FrameRelaySwitch = Depends(dep_node)):
@router.post("/{node_id}/duplicate", response_model=schemas.FrameRelaySwitch, status_code=status.HTTP_201_CREATED)
async def duplicate_frame_relay_switch(
destination_node_id: UUID = Body(..., embed=True), node: FrameRelaySwitch = Depends(dep_node)
):
"""
Duplicate a Frame Relay switch node.
"""
@@ -89,10 +89,10 @@ async def duplicate_frame_relay_switch(destination_node_id: UUID = Body(..., emb
return new_node.__json__()
@router.put("/{node_id}",
response_model=schemas.FrameRelaySwitch)
async def update_frame_relay_switch(node_data: schemas.FrameRelaySwitchUpdate,
node: FrameRelaySwitch = Depends(dep_node)):
@router.put("/{node_id}", response_model=schemas.FrameRelaySwitch)
async def update_frame_relay_switch(
node_data: schemas.FrameRelaySwitchUpdate, node: FrameRelaySwitch = Depends(dep_node)
):
"""
Update an Frame Relay switch node.
"""
@@ -106,8 +106,7 @@ async def update_frame_relay_switch(node_data: schemas.FrameRelaySwitchUpdate,
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)):
"""
Delete a Frame Relay switch node.
@@ -116,8 +115,7 @@ async def delete_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)):
await Dynamips.instance().delete_node(node.id)
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
def start_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)):
"""
Start a Frame Relay switch node.
@@ -127,8 +125,7 @@ def start_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)):
pass
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
def stop_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)):
"""
Stop a Frame Relay switch node.
@@ -138,8 +135,7 @@ def stop_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)):
pass
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
def suspend_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)):
"""
Suspend a Frame Relay switch node.
@@ -149,13 +145,14 @@ def suspend_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)):
pass
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def create_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO,
node: FrameRelaySwitch = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def create_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: FrameRelaySwitch = Depends(dep_node)
):
"""
Add a NIO (Network Input/Output) to the node.
The adapter number on the switch is always 0.
@@ -166,8 +163,7 @@ async def create_nio(adapter_number: int,
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_nio(adapter_number: int, port_number: int, node: FrameRelaySwitch = Depends(dep_node)):
"""
Remove a NIO (Network Input/Output) from the node.
@@ -179,10 +175,12 @@ async def delete_nio(adapter_number: int, port_number: int, node: FrameRelaySwit
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: FrameRelaySwitch = Depends(dep_node)):
async def start_capture(
adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: FrameRelaySwitch = Depends(dep_node),
):
"""
Start a packet capture on the node.
The adapter number on the switch is always 0.
@@ -193,8 +191,9 @@ async def start_capture(adapter_number: int,
return {"pcap_file_path": pcap_file_path}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT
)
async def stop_capture(adapter_number: int, port_number: int, node: FrameRelaySwitch = Depends(dep_node)):
"""
Stop a packet capture on the node.
+3 -6
View File
@@ -53,8 +53,7 @@ async def get_dynamips_images() -> List[str]:
return await dynamips_manager.list_images()
@router.post("/dynamips/images/{filename:path}",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/dynamips/images/{filename:path}", status_code=status.HTTP_204_NO_CONTENT)
async def upload_dynamips_image(filename: str, request: Request):
"""
Upload a Dynamips IOS image.
@@ -93,8 +92,7 @@ async def get_iou_images() -> List[str]:
return await iou_manager.list_images()
@router.post("/iou/images/{filename:path}",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/iou/images/{filename:path}", status_code=status.HTTP_204_NO_CONTENT)
async def upload_iou_image(filename: str, request: Request):
"""
Upload an IOU image.
@@ -130,8 +128,7 @@ async def get_qemu_images() -> List[str]:
return await qemu_manager.list_images()
@router.post("/qemu/images/{filename:path}",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/qemu/images/{filename:path}", status_code=status.HTTP_204_NO_CONTENT)
async def upload_qemu_image(filename: str, request: Request):
qemu_manager = Qemu.instance()
+54 -55
View File
@@ -30,9 +30,7 @@ from gns3server import schemas
from gns3server.compute.iou import IOU
from gns3server.compute.iou.iou_vm import IOUVM
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or IOU node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or IOU node"}}
router = APIRouter(responses=responses)
@@ -47,10 +45,12 @@ def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.IOU,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create IOU node"}})
@router.post(
"",
response_model=schemas.IOU,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create IOU node"}},
)
async def create_iou_node(project_id: UUID, node_data: schemas.IOUCreate):
"""
Create a new IOU node.
@@ -58,13 +58,15 @@ async def create_iou_node(project_id: UUID, node_data: schemas.IOUCreate):
iou = IOU.instance()
node_data = jsonable_encoder(node_data, exclude_unset=True)
vm = await iou.create_node(node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
application_id=node_data.get("application_id"),
path=node_data.get("path"),
console=node_data.get("console"),
console_type=node_data.get("console_type", "telnet"))
vm = await iou.create_node(
node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
application_id=node_data.get("application_id"),
path=node_data.get("path"),
console=node_data.get("console"),
console_type=node_data.get("console_type", "telnet"),
)
for name, value in node_data.items():
if hasattr(vm, name) and getattr(vm, name) != value:
@@ -80,8 +82,7 @@ async def create_iou_node(project_id: UUID, node_data: schemas.IOUCreate):
return vm.__json__()
@router.get("/{node_id}",
response_model=schemas.IOU)
@router.get("/{node_id}", response_model=schemas.IOU)
def get_iou_node(node: IOUVM = Depends(dep_node)):
"""
Return an IOU node.
@@ -90,8 +91,7 @@ def get_iou_node(node: IOUVM = Depends(dep_node)):
return node.__json__()
@router.put("/{node_id}",
response_model=schemas.IOU)
@router.put("/{node_id}", response_model=schemas.IOU)
async def update_iou_node(node_data: schemas.IOUUpdate, node: IOUVM = Depends(dep_node)):
"""
Update an IOU node.
@@ -112,8 +112,7 @@ async def update_iou_node(node_data: schemas.IOUUpdate, node: IOUVM = Depends(de
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_iou_node(node: IOUVM = Depends(dep_node)):
"""
Delete an IOU node.
@@ -122,9 +121,7 @@ async def delete_iou_node(node: IOUVM = Depends(dep_node)):
await IOU.instance().delete_node(node.id)
@router.post("/{node_id}/duplicate",
response_model=schemas.IOU,
status_code=status.HTTP_201_CREATED)
@router.post("/{node_id}/duplicate", response_model=schemas.IOU, status_code=status.HTTP_201_CREATED)
async def duplicate_iou_node(destination_node_id: UUID = Body(..., embed=True), node: IOUVM = Depends(dep_node)):
"""
Duplicate an IOU node.
@@ -134,8 +131,7 @@ async def duplicate_iou_node(destination_node_id: UUID = Body(..., embed=True),
return new_node.__json__()
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_iou_node(start_data: schemas.IOUStart, node: IOUVM = Depends(dep_node)):
"""
Start an IOU node.
@@ -150,8 +146,7 @@ async def start_iou_node(start_data: schemas.IOUStart, node: IOUVM = Depends(dep
return node.__json__()
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_iou_node(node: IOUVM = Depends(dep_node)):
"""
Stop an IOU node.
@@ -160,8 +155,7 @@ async def stop_iou_node(node: IOUVM = Depends(dep_node)):
await node.stop()
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
def suspend_iou_node(node: IOUVM = Depends(dep_node)):
"""
Suspend an IOU node.
@@ -171,8 +165,7 @@ def suspend_iou_node(node: IOUVM = Depends(dep_node)):
pass
@router.post("/{node_id}/reload",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_iou_node(node: IOUVM = Depends(dep_node)):
"""
Reload an IOU node.
@@ -181,13 +174,17 @@ async def reload_iou_node(node: IOUVM = Depends(dep_node)):
await node.reload()
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO])
async def create_iou_node_nio(adapter_number: int,
port_number: int,
nio_data: Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
node: IOUVM = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
)
async def create_iou_node_nio(
adapter_number: int,
port_number: int,
nio_data: Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
node: IOUVM = Depends(dep_node),
):
"""
Add a NIO (Network Input/Output) to the node.
"""
@@ -197,13 +194,17 @@ async def create_iou_node_nio(adapter_number: int,
return nio.__json__()
@router.put("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO])
async def update_iou_node_nio(adapter_number: int,
port_number: int,
nio_data: Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
node: IOUVM = Depends(dep_node)):
@router.put(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
)
async def update_iou_node_nio(
adapter_number: int,
port_number: int,
nio_data: Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
node: IOUVM = Depends(dep_node),
):
"""
Update a NIO (Network Input/Output) on the node.
"""
@@ -215,8 +216,7 @@ async def update_iou_node_nio(adapter_number: int,
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_iou_node_nio(adapter_number: int, port_number: int, node: IOUVM = Depends(dep_node)):
"""
Delete a NIO (Network Input/Output) from the node.
@@ -226,10 +226,9 @@ async def delete_iou_node_nio(adapter_number: int, port_number: int, node: IOUVM
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_iou_node_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: IOUVM = Depends(dep_node)):
async def start_iou_node_capture(
adapter_number: int, port_number: int, node_capture_data: schemas.NodeCapture, node: IOUVM = Depends(dep_node)
):
"""
Start a packet capture on the node.
"""
@@ -239,8 +238,9 @@ async def start_iou_node_capture(adapter_number: int,
return {"pcap_file_path": str(pcap_file_path)}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT
)
async def stop_iou_node_capture(adapter_number: int, port_number: int, node: IOUVM = Depends(dep_node)):
"""
Stop a packet capture on the node.
@@ -269,8 +269,7 @@ async def console_ws(websocket: WebSocket, node: IOUVM = Depends(dep_node)):
await node.start_websocket_console(websocket)
@router.post("/{node_id}/console/reset",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: IOUVM = Depends(dep_node)):
await node.reset_console()
+49 -46
View File
@@ -30,9 +30,7 @@ from gns3server import schemas
from gns3server.compute.builtin import Builtin
from gns3server.compute.builtin.nodes.nat import Nat
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or NAT node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or NAT node"}}
router = APIRouter(responses=responses)
@@ -47,10 +45,12 @@ def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.NAT,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create NAT node"}})
@router.post(
"",
response_model=schemas.NAT,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create NAT node"}},
)
async def create_nat_node(project_id: UUID, node_data: schemas.NATCreate):
"""
Create a new NAT node.
@@ -58,18 +58,19 @@ async def create_nat_node(project_id: UUID, node_data: schemas.NATCreate):
builtin_manager = Builtin.instance()
node_data = jsonable_encoder(node_data, exclude_unset=True)
node = await builtin_manager.create_node(node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_type="nat",
ports=node_data.get("ports_mapping"))
node = await builtin_manager.create_node(
node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_type="nat",
ports=node_data.get("ports_mapping"),
)
node.usage = node_data.get("usage", "")
return node.__json__()
@router.get("/{node_id}",
response_model=schemas.NAT)
@router.get("/{node_id}", response_model=schemas.NAT)
def get_nat_node(node: Nat = Depends(dep_node)):
"""
Return a NAT node.
@@ -78,8 +79,7 @@ def get_nat_node(node: Nat = Depends(dep_node)):
return node.__json__()
@router.put("/{node_id}",
response_model=schemas.NAT)
@router.put("/{node_id}", response_model=schemas.NAT)
def update_nat_node(node_data: schemas.NATUpdate, node: Nat = Depends(dep_node)):
"""
Update a NAT node.
@@ -93,8 +93,7 @@ def update_nat_node(node_data: schemas.NATUpdate, node: Nat = Depends(dep_node))
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_nat_node(node: Nat = Depends(dep_node)):
"""
Delete a cloud node.
@@ -103,8 +102,7 @@ async def delete_nat_node(node: Nat = Depends(dep_node)):
await Builtin.instance().delete_node(node.id)
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_nat_node(node: Nat = Depends(dep_node)):
"""
Start a NAT node.
@@ -113,8 +111,7 @@ async def start_nat_node(node: Nat = Depends(dep_node)):
await node.start()
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_nat_node(node: Nat = Depends(dep_node)):
"""
Stop a NAT node.
@@ -124,8 +121,7 @@ async def stop_nat_node(node: Nat = Depends(dep_node)):
pass
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_nat_node(node: Nat = Depends(dep_node)):
"""
Suspend a NAT node.
@@ -135,13 +131,17 @@ async def suspend_nat_node(node: Nat = Depends(dep_node)):
pass
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO])
async def create_nat_node_nio(adapter_number: int,
port_number: int,
nio_data: Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
node: Nat = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
)
async def create_nat_node_nio(
adapter_number: int,
port_number: int,
nio_data: Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
node: Nat = Depends(dep_node),
):
"""
Add a NIO (Network Input/Output) to the node.
The adapter number on the cloud is always 0.
@@ -152,13 +152,17 @@ async def create_nat_node_nio(adapter_number: int,
return nio.__json__()
@router.put("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO])
async def update_nat_node_nio(adapter_number: int,
port_number: int,
nio_data: Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
node: Nat = Depends(dep_node)):
@router.put(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
)
async def update_nat_node_nio(
adapter_number: int,
port_number: int,
nio_data: Union[schemas.EthernetNIO, schemas.TAPNIO, schemas.UDPNIO],
node: Nat = Depends(dep_node),
):
"""
Update a NIO (Network Input/Output) to the node.
The adapter number on the cloud is always 0.
@@ -171,8 +175,7 @@ async def update_nat_node_nio(adapter_number: int,
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_nat_node_nio(adapter_number: int, port_number: int, node: Nat = Depends(dep_node)):
"""
Remove a NIO (Network Input/Output) from the node.
@@ -183,10 +186,9 @@ async def delete_nat_node_nio(adapter_number: int, port_number: int, node: Nat =
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_nat_node_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: Nat = Depends(dep_node)):
async def start_nat_node_capture(
adapter_number: int, port_number: int, node_capture_data: schemas.NodeCapture, node: Nat = Depends(dep_node)
):
"""
Start a packet capture on the node.
The adapter number on the cloud is always 0.
@@ -197,8 +199,9 @@ async def start_nat_node_capture(adapter_number: int,
return {"pcap_file_path": pcap_file_path}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT
)
async def stop_nat_node_capture(adapter_number: int, port_number: int, node: Nat = Depends(dep_node)):
"""
Stop a packet capture on the node.
@@ -24,6 +24,7 @@ from websockets.exceptions import ConnectionClosed, WebSocketException
from gns3server.compute.notification_manager import NotificationManager
import logging
log = logging.getLogger(__name__)
router = APIRouter()
@@ -50,7 +51,7 @@ async def notification_ws(websocket: WebSocket):
await websocket.close()
if __name__ == '__main__':
if __name__ == "__main__":
import uvicorn
from fastapi import FastAPI
+15 -19
View File
@@ -21,6 +21,7 @@ API routes for projects.
import os
import logging
log = logging.getLogger()
from fastapi import APIRouter, Depends, HTTPException, Request, status
@@ -60,9 +61,7 @@ def get_compute_projects():
return [p.__json__() for p in pm.projects]
@router.post("/projects",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project)
@router.post("/projects", status_code=status.HTTP_201_CREATED, response_model=schemas.Project)
def create_compute_project(project_data: schemas.ProjectCreate):
"""
Create a new project on the compute.
@@ -70,15 +69,16 @@ def create_compute_project(project_data: schemas.ProjectCreate):
pm = ProjectManager.instance()
project_data = jsonable_encoder(project_data, exclude_unset=True)
project = pm.create_project(name=project_data.get("name"),
path=project_data.get("path"),
project_id=project_data.get("project_id"),
variables=project_data.get("variables", None))
project = pm.create_project(
name=project_data.get("name"),
path=project_data.get("path"),
project_id=project_data.get("project_id"),
variables=project_data.get("variables", None),
)
return project.__json__()
@router.put("/projects/{project_id}",
response_model=schemas.Project)
@router.put("/projects/{project_id}", response_model=schemas.Project)
async def update_compute_project(project_data: schemas.ProjectUpdate, project: Project = Depends(dep_project)):
"""
Update project on the compute.
@@ -88,8 +88,7 @@ async def update_compute_project(project_data: schemas.ProjectUpdate, project: P
return project.__json__()
@router.get("/projects/{project_id}",
response_model=schemas.Project)
@router.get("/projects/{project_id}", response_model=schemas.Project)
def get_compute_project(project: Project = Depends(dep_project)):
"""
Return a project from the compute.
@@ -98,8 +97,7 @@ def get_compute_project(project: Project = Depends(dep_project)):
return project.__json__()
@router.post("/projects/{project_id}/close",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/projects/{project_id}/close", status_code=status.HTTP_204_NO_CONTENT)
async def close_compute_project(project: Project = Depends(dep_project)):
"""
Close a project on the compute.
@@ -117,8 +115,7 @@ async def close_compute_project(project: Project = Depends(dep_project)):
log.warning("Skip project closing, another client is listening for project notifications")
@router.delete("/projects/{project_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/projects/{project_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_compute_project(project: Project = Depends(dep_project)):
"""
Delete project from the compute.
@@ -127,6 +124,7 @@ async def delete_compute_project(project: Project = Depends(dep_project)):
await project.delete()
ProjectManager.instance().remove_project(project.id)
# @Route.get(
# r"/projects/{project_id}/notifications",
# description="Receive notifications about the project",
@@ -181,8 +179,7 @@ async def delete_compute_project(project: Project = Depends(dep_project)):
# return {"action": "ping", "event": stats}
@router.get("/projects/{project_id}/files",
response_model=List[schemas.ProjectFile])
@router.get("/projects/{project_id}/files", response_model=List[schemas.ProjectFile])
async def get_compute_project_files(project: Project = Depends(dep_project)):
"""
Return files belonging to a project.
@@ -210,8 +207,7 @@ async def get_compute_project_file(file_path: str, project: Project = Depends(de
return FileResponse(path, media_type="application/octet-stream")
@router.post("/projects/{project_id}/files/{file_path:path}",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/projects/{project_id}/files/{file_path:path}", status_code=status.HTTP_204_NO_CONTENT)
async def write_compute_project_file(file_path: str, request: Request, project: Project = Depends(dep_project)):
path = os.path.normpath(file_path)
+56 -67
View File
@@ -31,9 +31,7 @@ from gns3server.compute.project_manager import ProjectManager
from gns3server.compute.qemu import Qemu
from gns3server.compute.qemu.qemu_vm import QemuVM
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or Qemu node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or Qemu node"}}
router = APIRouter(responses=responses)
@@ -48,10 +46,12 @@ def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.Qemu,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create Qemu node"}})
@router.post(
"",
response_model=schemas.Qemu,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create Qemu node"}},
)
async def create_qemu_node(project_id: UUID, node_data: schemas.QemuCreate):
"""
Create a new Qemu node.
@@ -59,16 +59,18 @@ async def create_qemu_node(project_id: UUID, node_data: schemas.QemuCreate):
qemu = Qemu.instance()
node_data = jsonable_encoder(node_data, exclude_unset=True)
vm = await qemu.create_node(node_data.pop("name"),
str(project_id),
node_data.pop("node_id", None),
linked_clone=node_data.get("linked_clone", True),
qemu_path=node_data.pop("qemu_path", None),
console=node_data.pop("console", None),
console_type=node_data.pop("console_type", "telnet"),
aux=node_data.get("aux"),
aux_type=node_data.pop("aux_type", "none"),
platform=node_data.pop("platform", None))
vm = await qemu.create_node(
node_data.pop("name"),
str(project_id),
node_data.pop("node_id", None),
linked_clone=node_data.get("linked_clone", True),
qemu_path=node_data.pop("qemu_path", None),
console=node_data.pop("console", None),
console_type=node_data.pop("console_type", "telnet"),
aux=node_data.get("aux"),
aux_type=node_data.pop("aux_type", "none"),
platform=node_data.pop("platform", None),
)
for name, value in node_data.items():
if hasattr(vm, name) and getattr(vm, name) != value:
@@ -77,8 +79,7 @@ async def create_qemu_node(project_id: UUID, node_data: schemas.QemuCreate):
return vm.__json__()
@router.get("/{node_id}",
response_model=schemas.Qemu)
@router.get("/{node_id}", response_model=schemas.Qemu)
def get_qemu_node(node: QemuVM = Depends(dep_node)):
"""
Return a Qemu node.
@@ -87,8 +88,7 @@ def get_qemu_node(node: QemuVM = Depends(dep_node)):
return node.__json__()
@router.put("/{node_id}",
response_model=schemas.Qemu)
@router.put("/{node_id}", response_model=schemas.Qemu)
async def update_qemu_node(node_data: schemas.QemuUpdate, node: QemuVM = Depends(dep_node)):
"""
Update a Qemu node.
@@ -104,8 +104,7 @@ async def update_qemu_node(node_data: schemas.QemuUpdate, node: QemuVM = Depends
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_qemu_node(node: QemuVM = Depends(dep_node)):
"""
Delete a Qemu node.
@@ -114,9 +113,7 @@ async def delete_qemu_node(node: QemuVM = Depends(dep_node)):
await Qemu.instance().delete_node(node.id)
@router.post("/{node_id}/duplicate",
response_model=schemas.Qemu,
status_code=status.HTTP_201_CREATED)
@router.post("/{node_id}/duplicate", response_model=schemas.Qemu, status_code=status.HTTP_201_CREATED)
async def duplicate_qemu_node(destination_node_id: UUID = Body(..., embed=True), node: QemuVM = Depends(dep_node)):
"""
Duplicate a Qemu node.
@@ -126,15 +123,13 @@ async def duplicate_qemu_node(destination_node_id: UUID = Body(..., embed=True),
return new_node.__json__()
@router.post("/{node_id}/resize_disk",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/resize_disk", status_code=status.HTTP_204_NO_CONTENT)
async def resize_qemu_node_disk(node_data: schemas.QemuDiskResize, node: QemuVM = Depends(dep_node)):
await node.resize_disk(node_data.drive_name, node_data.extend)
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_qemu_node(node: QemuVM = Depends(dep_node)):
"""
Start a Qemu node.
@@ -145,13 +140,12 @@ async def start_qemu_node(node: QemuVM = Depends(dep_node)):
if hardware_accel and "-no-kvm" not in node.options and "-no-hax" not in node.options:
pm = ProjectManager.instance()
if pm.check_hardware_virtualization(node) is False:
pass #FIXME: check this
#raise ComputeError("Cannot start VM with hardware acceleration (KVM/HAX) enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
pass # FIXME: check this
# raise ComputeError("Cannot start VM with hardware acceleration (KVM/HAX) enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
await node.start()
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_qemu_node(node: QemuVM = Depends(dep_node)):
"""
Stop a Qemu node.
@@ -160,8 +154,7 @@ async def stop_qemu_node(node: QemuVM = Depends(dep_node)):
await node.stop()
@router.post("/{node_id}/reload",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_qemu_node(node: QemuVM = Depends(dep_node)):
"""
Reload a Qemu node.
@@ -170,8 +163,7 @@ async def reload_qemu_node(node: QemuVM = Depends(dep_node)):
await node.reload()
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_qemu_node(node: QemuVM = Depends(dep_node)):
"""
Suspend a Qemu node.
@@ -180,8 +172,7 @@ async def suspend_qemu_node(node: QemuVM = Depends(dep_node)):
await node.suspend()
@router.post("/{node_id}/resume",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/resume", status_code=status.HTTP_204_NO_CONTENT)
async def resume_qemu_node(node: QemuVM = Depends(dep_node)):
"""
Resume a Qemu node.
@@ -190,13 +181,14 @@ async def resume_qemu_node(node: QemuVM = Depends(dep_node)):
await node.resume()
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def create_qemu_node_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO,
node: QemuVM = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def create_qemu_node_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: QemuVM = Depends(dep_node)
):
"""
Add a NIO (Network Input/Output) to the node.
The port number on the Qemu node is always 0.
@@ -207,13 +199,14 @@ async def create_qemu_node_nio(adapter_number: int,
return nio.__json__()
@router.put("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def update_qemu_node_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO,
node: QemuVM = Depends(dep_node)):
@router.put(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def update_qemu_node_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: QemuVM = Depends(dep_node)
):
"""
Update a NIO (Network Input/Output) on the node.
The port number on the Qemu node is always 0.
@@ -228,11 +221,8 @@ async def update_qemu_node_nio(adapter_number: int,
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
async def delete_qemu_node_nio(adapter_number: int,
port_number: int,
node: QemuVM = Depends(dep_node)):
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_qemu_node_nio(adapter_number: int, port_number: int, node: QemuVM = Depends(dep_node)):
"""
Delete a NIO (Network Input/Output) from the node.
The port number on the Qemu node is always 0.
@@ -242,10 +232,9 @@ async def delete_qemu_node_nio(adapter_number: int,
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_qemu_node_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: QemuVM = Depends(dep_node)):
async def start_qemu_node_capture(
adapter_number: int, port_number: int, node_capture_data: schemas.NodeCapture, node: QemuVM = Depends(dep_node)
):
"""
Start a packet capture on the node.
The port number on the Qemu node is always 0.
@@ -256,8 +245,9 @@ async def start_qemu_node_capture(adapter_number: int,
return {"pcap_file_path": str(pcap_file_path)}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT
)
async def stop_qemu_node_capture(adapter_number: int, port_number: int, node: QemuVM = Depends(dep_node)):
"""
Stop a packet capture on the node.
@@ -288,8 +278,7 @@ async def console_ws(websocket: WebSocket, node: QemuVM = Depends(dep_node)):
await node.start_websocket_console(websocket)
@router.post("/{node_id}/console/reset",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: QemuVM = Depends(dep_node)):
await node.reset_console()
@@ -31,9 +31,7 @@ from gns3server.compute.virtualbox.virtualbox_error import VirtualBoxError
from gns3server.compute.project_manager import ProjectManager
from gns3server.compute.virtualbox.virtualbox_vm import VirtualBoxVM
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or VirtualBox node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or VirtualBox node"}}
router = APIRouter(responses=responses)
@@ -48,10 +46,12 @@ def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.VirtualBox,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create VirtualBox node"}})
@router.post(
"",
response_model=schemas.VirtualBox,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create VirtualBox node"}},
)
async def create_virtualbox_node(project_id: UUID, node_data: schemas.VirtualBoxCreate):
"""
Create a new VirtualBox node.
@@ -59,14 +59,16 @@ async def create_virtualbox_node(project_id: UUID, node_data: schemas.VirtualBox
vbox_manager = VirtualBox.instance()
node_data = jsonable_encoder(node_data, exclude_unset=True)
vm = await vbox_manager.create_node(node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_data.pop("vmname"),
linked_clone=node_data.pop("linked_clone", False),
console=node_data.get("console", None),
console_type=node_data.get("console_type", "telnet"),
adapters=node_data.get("adapters", 0))
vm = await vbox_manager.create_node(
node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_data.pop("vmname"),
linked_clone=node_data.pop("linked_clone", False),
console=node_data.get("console", None),
console_type=node_data.get("console_type", "telnet"),
adapters=node_data.get("adapters", 0),
)
if "ram" in node_data:
ram = node_data.pop("ram")
@@ -81,8 +83,7 @@ async def create_virtualbox_node(project_id: UUID, node_data: schemas.VirtualBox
return vm.__json__()
@router.get("/{node_id}",
response_model=schemas.VirtualBox)
@router.get("/{node_id}", response_model=schemas.VirtualBox)
def get_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
"""
Return a VirtualBox node.
@@ -91,8 +92,7 @@ def get_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
return node.__json__()
@router.put("/{node_id}",
response_model=schemas.VirtualBox)
@router.put("/{node_id}", response_model=schemas.VirtualBox)
async def update_virtualbox_node(node_data: schemas.VirtualBoxUpdate, node: VirtualBoxVM = Depends(dep_node)):
"""
Update a VirtualBox node.
@@ -134,8 +134,7 @@ async def update_virtualbox_node(node_data: schemas.VirtualBoxUpdate, node: Virt
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
"""
Delete a VirtualBox node.
@@ -144,8 +143,7 @@ async def delete_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
await VirtualBox.instance().delete_node(node.id)
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
"""
Start a VirtualBox node.
@@ -155,12 +153,11 @@ async def start_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
pm = ProjectManager.instance()
if pm.check_hardware_virtualization(node) is False:
pass # FIXME: check this
#raise ComputeError("Cannot start VM with hardware acceleration (KVM/HAX) enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
# raise ComputeError("Cannot start VM with hardware acceleration (KVM/HAX) enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
await node.start()
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
"""
Stop a VirtualBox node.
@@ -169,8 +166,7 @@ async def stop_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
await node.stop()
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
"""
Suspend a VirtualBox node.
@@ -179,8 +175,7 @@ async def suspend_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
await node.suspend()
@router.post("/{node_id}/resume",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/resume", status_code=status.HTTP_204_NO_CONTENT)
async def resume_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
"""
Resume a VirtualBox node.
@@ -189,8 +184,7 @@ async def resume_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
await node.resume()
@router.post("/{node_id}/reload",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
"""
Reload a VirtualBox node.
@@ -199,13 +193,14 @@ async def reload_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)):
await node.reload()
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def create_virtualbox_node_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO,
node: VirtualBoxVM = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def create_virtualbox_node_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: VirtualBoxVM = Depends(dep_node)
):
"""
Add a NIO (Network Input/Output) to the node.
The port number on the VirtualBox node is always 0.
@@ -216,13 +211,14 @@ async def create_virtualbox_node_nio(adapter_number: int,
return nio.__json__()
@router.put("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def update_virtualbox_node_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO,
node: VirtualBoxVM = Depends(dep_node)):
@router.put(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def update_virtualbox_node_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: VirtualBoxVM = Depends(dep_node)
):
"""
Update a NIO (Network Input/Output) on the node.
The port number on the VirtualBox node is always 0.
@@ -237,8 +233,7 @@ async def update_virtualbox_node_nio(adapter_number: int,
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_virtualbox_node_nio(adapter_number: int, port_number: int, node: VirtualBoxVM = Depends(dep_node)):
"""
Delete a NIO (Network Input/Output) from the node.
@@ -249,10 +244,12 @@ async def delete_virtualbox_node_nio(adapter_number: int, port_number: int, node
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_virtualbox_node_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: VirtualBoxVM = Depends(dep_node)):
async def start_virtualbox_node_capture(
adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: VirtualBoxVM = Depends(dep_node),
):
"""
Start a packet capture on the node.
The port number on the VirtualBox node is always 0.
@@ -263,8 +260,9 @@ async def start_virtualbox_node_capture(adapter_number: int,
return {"pcap_file_path": str(pcap_file_path)}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT
)
async def stop_virtualbox_node_capture(adapter_number: int, port_number: int, node: VirtualBoxVM = Depends(dep_node)):
"""
Stop a packet capture on the node.
@@ -295,8 +293,7 @@ async def console_ws(websocket: WebSocket, node: VirtualBoxVM = Depends(dep_node
await node.start_websocket_console(websocket)
@router.post("/{node_id}/console/reset",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: VirtualBoxVM = Depends(dep_node)):
await node.reset_console()
+51 -57
View File
@@ -30,9 +30,7 @@ from gns3server.compute.vmware import VMware
from gns3server.compute.project_manager import ProjectManager
from gns3server.compute.vmware.vmware_vm import VMwareVM
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or VMware node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or VMware node"}}
router = APIRouter(responses=responses)
@@ -47,10 +45,12 @@ def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.VMware,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create VMware node"}})
@router.post(
"",
response_model=schemas.VMware,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create VMware node"}},
)
async def create_vmware_node(project_id: UUID, node_data: schemas.VMwareCreate):
"""
Create a new VMware node.
@@ -58,13 +58,15 @@ async def create_vmware_node(project_id: UUID, node_data: schemas.VMwareCreate):
vmware_manager = VMware.instance()
node_data = jsonable_encoder(node_data, exclude_unset=True)
vm = await vmware_manager.create_node(node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_data.pop("vmx_path"),
linked_clone=node_data.pop("linked_clone"),
console=node_data.get("console", None),
console_type=node_data.get("console_type", "telnet"))
vm = await vmware_manager.create_node(
node_data.pop("name"),
str(project_id),
node_data.get("node_id"),
node_data.pop("vmx_path"),
linked_clone=node_data.pop("linked_clone"),
console=node_data.get("console", None),
console_type=node_data.get("console_type", "telnet"),
)
for name, value in node_data.items():
if name != "node_id":
@@ -74,8 +76,7 @@ async def create_vmware_node(project_id: UUID, node_data: schemas.VMwareCreate):
return vm.__json__()
@router.get("/{node_id}",
response_model=schemas.VMware)
@router.get("/{node_id}", response_model=schemas.VMware)
def get_vmware_node(node: VMwareVM = Depends(dep_node)):
"""
Return a VMware node.
@@ -84,8 +85,7 @@ def get_vmware_node(node: VMwareVM = Depends(dep_node)):
return node.__json__()
@router.put("/{node_id}",
response_model=schemas.VMware)
@router.put("/{node_id}", response_model=schemas.VMware)
def update_vmware_node(node_data: schemas.VMwareUpdate, node: VMwareVM = Depends(dep_node)):
"""
Update a VMware node.
@@ -102,8 +102,7 @@ def update_vmware_node(node_data: schemas.VMwareUpdate, node: VMwareVM = Depends
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_vmware_node(node: VMwareVM = Depends(dep_node)):
"""
Delete a VMware node.
@@ -112,8 +111,7 @@ async def delete_vmware_node(node: VMwareVM = Depends(dep_node)):
await VMware.instance().delete_node(node.id)
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_vmware_node(node: VMwareVM = Depends(dep_node)):
"""
Start a VMware node.
@@ -122,13 +120,12 @@ async def start_vmware_node(node: VMwareVM = Depends(dep_node)):
if node.check_hw_virtualization():
pm = ProjectManager.instance()
if pm.check_hardware_virtualization(node) is False:
pass # FIXME: check this
#raise ComputeError("Cannot start VM with hardware acceleration (KVM/HAX) enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
pass # FIXME: check this
# raise ComputeError("Cannot start VM with hardware acceleration (KVM/HAX) enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
await node.start()
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_vmware_node(node: VMwareVM = Depends(dep_node)):
"""
Stop a VMware node.
@@ -137,8 +134,7 @@ async def stop_vmware_node(node: VMwareVM = Depends(dep_node)):
await node.stop()
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_vmware_node(node: VMwareVM = Depends(dep_node)):
"""
Suspend a VMware node.
@@ -147,8 +143,7 @@ async def suspend_vmware_node(node: VMwareVM = Depends(dep_node)):
await node.suspend()
@router.post("/{node_id}/resume",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/resume", status_code=status.HTTP_204_NO_CONTENT)
async def resume_vmware_node(node: VMwareVM = Depends(dep_node)):
"""
Resume a VMware node.
@@ -157,8 +152,7 @@ async def resume_vmware_node(node: VMwareVM = Depends(dep_node)):
await node.resume()
@router.post("/{node_id}/reload",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_vmware_node(node: VMwareVM = Depends(dep_node)):
"""
Reload a VMware node.
@@ -167,13 +161,14 @@ async def reload_vmware_node(node: VMwareVM = Depends(dep_node)):
await node.reload()
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def create_vmware_node_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO,
node: VMwareVM = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def create_vmware_node_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: VMwareVM = Depends(dep_node)
):
"""
Add a NIO (Network Input/Output) to the node.
The port number on the VMware node is always 0.
@@ -184,12 +179,14 @@ async def create_vmware_node_nio(adapter_number: int,
return nio.__json__()
@router.put("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def update_vmware_node_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO, node: VMwareVM = Depends(dep_node)):
@router.put(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def update_vmware_node_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: VMwareVM = Depends(dep_node)
):
"""
Update a NIO (Network Input/Output) on the node.
The port number on the VMware node is always 0.
@@ -202,8 +199,7 @@ async def update_vmware_node_nio(adapter_number: int,
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_vmware_node_nio(adapter_number: int, port_number: int, node: VMwareVM = Depends(dep_node)):
"""
Delete a NIO (Network Input/Output) from the node.
@@ -214,10 +210,9 @@ async def delete_vmware_node_nio(adapter_number: int, port_number: int, node: VM
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_vmware_node_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: VMwareVM = Depends(dep_node)):
async def start_vmware_node_capture(
adapter_number: int, port_number: int, node_capture_data: schemas.NodeCapture, node: VMwareVM = Depends(dep_node)
):
"""
Start a packet capture on the node.
The port number on the VMware node is always 0.
@@ -228,8 +223,9 @@ async def start_vmware_node_capture(adapter_number: int,
return {"pcap_file_path": pcap_file_path}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT
)
async def stop_vmware_node_capture(adapter_number: int, port_number: int, node: VMwareVM = Depends(dep_node)):
"""
Stop a packet capture on the node.
@@ -251,8 +247,7 @@ async def stream_pcap_file(adapter_number: int, port_number: int, node: VMwareVM
return StreamingResponse(stream, media_type="application/vnd.tcpdump.pcap")
@router.post("/{node_id}/interfaces/vmnet",
status_code=status.HTTP_201_CREATED)
@router.post("/{node_id}/interfaces/vmnet", status_code=status.HTTP_201_CREATED)
def allocate_vmnet(node: VMwareVM = Depends(dep_node)) -> dict:
"""
Allocate a VMware VMnet interface on the server.
@@ -274,8 +269,7 @@ async def console_ws(websocket: WebSocket, node: VMwareVM = Depends(dep_node)):
await node.start_websocket_console(websocket)
@router.post("/{node_id}/console/reset",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: VMwareVM = Depends(dep_node)):
await node.reset_console()
+48 -57
View File
@@ -29,9 +29,7 @@ from gns3server import schemas
from gns3server.compute.vpcs import VPCS
from gns3server.compute.vpcs.vpcs_vm import VPCSVM
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or VMware node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or VMware node"}}
router = APIRouter(responses=responses)
@@ -46,10 +44,12 @@ def dep_node(project_id: UUID, node_id: UUID):
return node
@router.post("",
response_model=schemas.VPCS,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create VMware node"}})
@router.post(
"",
response_model=schemas.VPCS,
status_code=status.HTTP_201_CREATED,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create VMware node"}},
)
async def create_vpcs_node(project_id: UUID, node_data: schemas.VPCSCreate):
"""
Create a new VPCS node.
@@ -57,18 +57,19 @@ async def create_vpcs_node(project_id: UUID, node_data: schemas.VPCSCreate):
vpcs = VPCS.instance()
node_data = jsonable_encoder(node_data, exclude_unset=True)
vm = await vpcs.create_node(node_data["name"],
str(project_id),
node_data.get("node_id"),
console=node_data.get("console"),
console_type=node_data.get("console_type", "telnet"),
startup_script=node_data.get("startup_script"))
vm = await vpcs.create_node(
node_data["name"],
str(project_id),
node_data.get("node_id"),
console=node_data.get("console"),
console_type=node_data.get("console_type", "telnet"),
startup_script=node_data.get("startup_script"),
)
return vm.__json__()
@router.get("/{node_id}",
response_model=schemas.VPCS)
@router.get("/{node_id}", response_model=schemas.VPCS)
def get_vpcs_node(node: VPCSVM = Depends(dep_node)):
"""
Return a VPCS node.
@@ -77,8 +78,7 @@ def get_vpcs_node(node: VPCSVM = Depends(dep_node)):
return node.__json__()
@router.put("/{node_id}",
response_model=schemas.VPCS)
@router.put("/{node_id}", response_model=schemas.VPCS)
def update_vpcs_node(node_data: schemas.VPCSUpdate, node: VPCSVM = Depends(dep_node)):
"""
Update a VPCS node.
@@ -92,8 +92,7 @@ def update_vpcs_node(node_data: schemas.VPCSUpdate, node: VPCSVM = Depends(dep_n
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_vpcs_node(node: VPCSVM = Depends(dep_node)):
"""
Delete a VPCS node.
@@ -102,9 +101,7 @@ async def delete_vpcs_node(node: VPCSVM = Depends(dep_node)):
await VPCS.instance().delete_node(node.id)
@router.post("/{node_id}/duplicate",
response_model=schemas.VPCS,
status_code=status.HTTP_201_CREATED)
@router.post("/{node_id}/duplicate", response_model=schemas.VPCS, status_code=status.HTTP_201_CREATED)
async def duplicate_vpcs_node(destination_node_id: UUID = Body(..., embed=True), node: VPCSVM = Depends(dep_node)):
"""
Duplicate a VPCS node.
@@ -114,8 +111,7 @@ async def duplicate_vpcs_node(destination_node_id: UUID = Body(..., embed=True),
return new_node.__json__()
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_vpcs_node(node: VPCSVM = Depends(dep_node)):
"""
Start a VPCS node.
@@ -124,8 +120,7 @@ async def start_vpcs_node(node: VPCSVM = Depends(dep_node)):
await node.start()
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_vpcs_node(node: VPCSVM = Depends(dep_node)):
"""
Stop a VPCS node.
@@ -134,8 +129,7 @@ async def stop_vpcs_node(node: VPCSVM = Depends(dep_node)):
await node.stop()
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_vpcs_node(node: VPCSVM = Depends(dep_node)):
"""
Suspend a VPCS node.
@@ -145,8 +139,7 @@ async def suspend_vpcs_node(node: VPCSVM = Depends(dep_node)):
pass
@router.post("/{node_id}/reload",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_vpcs_node(node: VPCSVM = Depends(dep_node)):
"""
Reload a VPCS node.
@@ -155,13 +148,14 @@ async def reload_vpcs_node(node: VPCSVM = Depends(dep_node)):
await node.reload()
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def create_vpcs_node_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO,
node: VPCSVM = Depends(dep_node)):
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def create_vpcs_node_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: VPCSVM = Depends(dep_node)
):
"""
Add a NIO (Network Input/Output) to the node.
The adapter number on the VPCS node is always 0.
@@ -172,13 +166,14 @@ async def create_vpcs_node_nio(adapter_number: int,
return nio.__json__()
@router.put("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO)
async def update_vpcs_node_nio(adapter_number: int,
port_number: int,
nio_data: schemas.UDPNIO,
node: VPCSVM = Depends(dep_node)):
@router.put(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_201_CREATED,
response_model=schemas.UDPNIO,
)
async def update_vpcs_node_nio(
adapter_number: int, port_number: int, nio_data: schemas.UDPNIO, node: VPCSVM = Depends(dep_node)
):
"""
Update a NIO (Network Input/Output) on the node.
The adapter number on the VPCS node is always 0.
@@ -191,11 +186,8 @@ async def update_vpcs_node_nio(adapter_number: int,
return nio.__json__()
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio",
status_code=status.HTTP_204_NO_CONTENT)
async def delete_vpcs_node_nio(adapter_number: int,
port_number: int,
node: VPCSVM = Depends(dep_node)):
@router.delete("/{node_id}/adapters/{adapter_number}/ports/{port_number}/nio", status_code=status.HTTP_204_NO_CONTENT)
async def delete_vpcs_node_nio(adapter_number: int, port_number: int, node: VPCSVM = Depends(dep_node)):
"""
Delete a NIO (Network Input/Output) from the node.
The adapter number on the VPCS node is always 0.
@@ -205,10 +197,9 @@ async def delete_vpcs_node_nio(adapter_number: int,
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
async def start_vpcs_node_capture(adapter_number: int,
port_number: int,
node_capture_data: schemas.NodeCapture,
node: VPCSVM = Depends(dep_node)):
async def start_vpcs_node_capture(
adapter_number: int, port_number: int, node_capture_data: schemas.NodeCapture, node: VPCSVM = Depends(dep_node)
):
"""
Start a packet capture on the node.
The adapter number on the VPCS node is always 0.
@@ -219,8 +210,9 @@ async def start_vpcs_node_capture(adapter_number: int,
return {"pcap_file_path": pcap_file_path}
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stop", status_code=status.HTTP_204_NO_CONTENT
)
async def stop_vpcs_node_capture(adapter_number: int, port_number: int, node: VPCSVM = Depends(dep_node)):
"""
Stop a packet capture on the node.
@@ -230,8 +222,7 @@ async def stop_vpcs_node_capture(adapter_number: int, port_number: int, node: VP
await node.stop_capture(port_number)
@router.post("/{node_id}/console/reset",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: VPCSVM = Depends(dep_node)):
await node.reset_console()
@@ -25,12 +25,13 @@ router = APIRouter()
@router.get("")
async def get_appliances(update: Optional[bool] = None, symbol_theme: Optional[str] = "Classic"):
async def get_appliances(update: Optional[bool] = None, symbol_theme: Optional[str] = "Classic"):
"""
Return all appliances known by the controller.
"""
from gns3server.controller import Controller
controller = Controller.instance()
if update:
await controller.appliance_manager.download_appliances()
+24 -34
View File
@@ -29,22 +29,24 @@ from gns3server import schemas
from .dependencies.database import get_repository
responses = {
404: {"model": schemas.ErrorMessage, "description": "Compute not found"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Compute not found"}}
router = APIRouter(responses=responses)
@router.post("",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Compute,
responses={404: {"model": schemas.ErrorMessage, "description": "Could not connect to compute"},
409: {"model": schemas.ErrorMessage, "description": "Could not create compute"},
401: {"model": schemas.ErrorMessage, "description": "Invalid authentication for compute"}})
@router.post(
"",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Compute,
responses={
404: {"model": schemas.ErrorMessage, "description": "Could not connect to compute"},
409: {"model": schemas.ErrorMessage, "description": "Could not create compute"},
401: {"model": schemas.ErrorMessage, "description": "Invalid authentication for compute"},
},
)
async def create_compute(
compute_create: schemas.ComputeCreate,
computes_repo: ComputesRepository = Depends(get_repository(ComputesRepository))
compute_create: schemas.ComputeCreate,
computes_repo: ComputesRepository = Depends(get_repository(ComputesRepository)),
) -> schemas.Compute:
"""
Create a new compute on the controller.
@@ -53,12 +55,9 @@ async def create_compute(
return await ComputesService(computes_repo).create_compute(compute_create)
@router.get("/{compute_id}",
response_model=schemas.Compute,
response_model_exclude_unset=True)
@router.get("/{compute_id}", response_model=schemas.Compute, response_model_exclude_unset=True)
async def get_compute(
compute_id: Union[str, UUID],
computes_repo: ComputesRepository = Depends(get_repository(ComputesRepository))
compute_id: Union[str, UUID], computes_repo: ComputesRepository = Depends(get_repository(ComputesRepository))
) -> schemas.Compute:
"""
Return a compute from the controller.
@@ -67,11 +66,9 @@ async def get_compute(
return await ComputesService(computes_repo).get_compute(compute_id)
@router.get("",
response_model=List[schemas.Compute],
response_model_exclude_unset=True)
@router.get("", response_model=List[schemas.Compute], response_model_exclude_unset=True)
async def get_computes(
computes_repo: ComputesRepository = Depends(get_repository(ComputesRepository))
computes_repo: ComputesRepository = Depends(get_repository(ComputesRepository)),
) -> List[schemas.Compute]:
"""
Return all computes known by the controller.
@@ -80,13 +77,11 @@ async def get_computes(
return await ComputesService(computes_repo).get_computes()
@router.put("/{compute_id}",
response_model=schemas.Compute,
response_model_exclude_unset=True)
@router.put("/{compute_id}", response_model=schemas.Compute, response_model_exclude_unset=True)
async def update_compute(
compute_id: Union[str, UUID],
compute_update: schemas.ComputeUpdate,
computes_repo: ComputesRepository = Depends(get_repository(ComputesRepository))
compute_id: Union[str, UUID],
compute_update: schemas.ComputeUpdate,
computes_repo: ComputesRepository = Depends(get_repository(ComputesRepository)),
) -> schemas.Compute:
"""
Update a compute on the controller.
@@ -95,11 +90,9 @@ async def update_compute(
return await ComputesService(computes_repo).update_compute(compute_id, compute_update)
@router.delete("/{compute_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{compute_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_compute(
compute_id: Union[str, UUID],
computes_repo: ComputesRepository = Depends(get_repository(ComputesRepository))
compute_id: Union[str, UUID], computes_repo: ComputesRepository = Depends(get_repository(ComputesRepository))
):
"""
Delete a compute from the controller.
@@ -160,7 +153,4 @@ async def autoidlepc(compute_id: Union[str, UUID], auto_idle_pc: schemas.AutoIdl
"""
controller = Controller.instance()
return await controller.autoidlepc(str(compute_id),
auto_idle_pc.platform,
auto_idle_pc.image,
auto_idle_pc.ram)
return await controller.autoidlepc(str(compute_id), auto_idle_pc.platform, auto_idle_pc.image, auto_idle_pc.ram)
+16 -14
View File
@@ -29,14 +29,17 @@ from gns3server import schemas
import logging
log = logging.getLogger(__name__)
router = APIRouter()
@router.post("/shutdown",
status_code=status.HTTP_204_NO_CONTENT,
responses={403: {"model": schemas.ErrorMessage, "description": "Server shutdown not allowed"}})
@router.post(
"/shutdown",
status_code=status.HTTP_204_NO_CONTENT,
responses={403: {"model": schemas.ErrorMessage, "description": "Server shutdown not allowed"}},
)
async def shutdown():
"""
Shutdown the local server
@@ -67,8 +70,7 @@ async def shutdown():
os.kill(os.getpid(), signal.SIGTERM)
@router.get("/version",
response_model=schemas.Version)
@router.get("/version", response_model=schemas.Version)
def get_version():
"""
Return the server version number.
@@ -78,10 +80,12 @@ def get_version():
return {"version": __version__, "local": local_server}
@router.post("/version",
response_model=schemas.Version,
response_model_exclude_defaults=True,
responses={409: {"model": schemas.ErrorMessage, "description": "Invalid version"}})
@router.post(
"/version",
response_model=schemas.Version,
response_model_exclude_defaults=True,
responses={409: {"model": schemas.ErrorMessage, "description": "Invalid version"}},
)
def check_version(version: schemas.Version):
"""
Check if version is the same as the server.
@@ -97,8 +101,7 @@ def check_version(version: schemas.Version):
return {"version": __version__}
@router.get("/iou_license",
response_model=schemas.IOULicense)
@router.get("/iou_license", response_model=schemas.IOULicense)
def get_iou_license():
"""
Return the IOU license settings
@@ -107,9 +110,7 @@ def get_iou_license():
return Controller.instance().iou_license
@router.put("/iou_license",
status_code=status.HTTP_201_CREATED,
response_model=schemas.IOULicense)
@router.put("/iou_license", status_code=status.HTTP_201_CREATED, response_model=schemas.IOULicense)
async def update_iou_license(iou_license: schemas.IOULicense):
"""
Update the IOU license settings.
@@ -137,6 +138,7 @@ async def statistics():
log.error(f"Could not retrieve statistics on compute {compute.name}: {e}")
return compute_statistics
# @Route.post(
# r"/debug",
# description="Dump debug information to disk (debug directory in config directory). Work only for local server",
@@ -28,8 +28,7 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/v3/users/login") # FIXME: URL p
async def get_user_from_token(
token: str = Depends(oauth2_scheme),
user_repo: UsersRepository = Depends(get_repository(UsersRepository))
token: str = Depends(oauth2_scheme), user_repo: UsersRepository = Depends(get_repository(UsersRepository))
) -> schemas.User:
username = auth_service.get_username_from_token(token)
@@ -38,7 +37,7 @@ async def get_user_from_token(
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"}
headers={"WWW-Authenticate": "Bearer"},
)
return user
@@ -49,6 +48,6 @@ async def get_current_active_user(current_user: schemas.User = Depends(get_user_
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Not an active user",
headers={"WWW-Authenticate": "Bearer"}
headers={"WWW-Authenticate": "Bearer"},
)
return current_user
@@ -31,7 +31,7 @@ async def get_db_session(request: Request) -> AsyncSession:
def get_repository(repo: Type[BaseRepository]) -> Callable:
def get_repo(db_session: AsyncSession = Depends(get_db_session)) -> Type[BaseRepository]:
return repo(db_session)
return get_repo
+6 -17
View File
@@ -26,16 +26,12 @@ from uuid import UUID
from gns3server.controller import Controller
from gns3server import schemas
responses = {
404: {"model": schemas.ErrorMessage, "description": "Project or drawing not found"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Project or drawing not found"}}
router = APIRouter(responses=responses)
@router.get("",
response_model=List[schemas.Drawing],
response_model_exclude_unset=True)
@router.get("", response_model=List[schemas.Drawing], response_model_exclude_unset=True)
async def get_drawings(project_id: UUID):
"""
Return the list of all drawings for a given project.
@@ -45,9 +41,7 @@ async def get_drawings(project_id: UUID):
return [v.__json__() for v in project.drawings.values()]
@router.post("",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Drawing)
@router.post("", status_code=status.HTTP_201_CREATED, response_model=schemas.Drawing)
async def create_drawing(project_id: UUID, drawing_data: schemas.Drawing):
"""
Create a new drawing.
@@ -58,9 +52,7 @@ async def create_drawing(project_id: UUID, drawing_data: schemas.Drawing):
return drawing.__json__()
@router.get("/{drawing_id}",
response_model=schemas.Drawing,
response_model_exclude_unset=True)
@router.get("/{drawing_id}", response_model=schemas.Drawing, response_model_exclude_unset=True)
async def get_drawing(project_id: UUID, drawing_id: UUID):
"""
Return a drawing.
@@ -71,9 +63,7 @@ async def get_drawing(project_id: UUID, drawing_id: UUID):
return drawing.__json__()
@router.put("/{drawing_id}",
response_model=schemas.Drawing,
response_model_exclude_unset=True)
@router.put("/{drawing_id}", response_model=schemas.Drawing, response_model_exclude_unset=True)
async def update_drawing(project_id: UUID, drawing_id: UUID, drawing_data: schemas.Drawing):
"""
Update a drawing.
@@ -85,8 +75,7 @@ async def update_drawing(project_id: UUID, drawing_id: UUID, drawing_data: schem
return drawing.__json__()
@router.delete("/{drawing_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{drawing_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_drawing(project_id: UUID, drawing_id: UUID):
"""
Delete a drawing.
+30 -34
View File
@@ -34,11 +34,10 @@ from gns3server.utils.http_client import HTTPClient
from gns3server import schemas
import logging
log = logging.getLogger(__name__)
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or link"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or link"}}
router = APIRouter(responses=responses)
@@ -53,9 +52,7 @@ async def dep_link(project_id: UUID, link_id: UUID):
return link
@router.get("",
response_model=List[schemas.Link],
response_model_exclude_unset=True)
@router.get("", response_model=List[schemas.Link], response_model_exclude_unset=True)
async def get_links(project_id: UUID):
"""
Return all links for a given project.
@@ -65,11 +62,15 @@ async def get_links(project_id: UUID):
return [v.__json__() for v in project.links.values()]
@router.post("",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Link,
responses={404: {"model": schemas.ErrorMessage, "description": "Could not find project"},
409: {"model": schemas.ErrorMessage, "description": "Could not create link"}})
@router.post(
"",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Link,
responses={
404: {"model": schemas.ErrorMessage, "description": "Could not find project"},
409: {"model": schemas.ErrorMessage, "description": "Could not create link"},
},
)
async def create_link(project_id: UUID, link_data: schemas.Link):
"""
Create a new link.
@@ -84,10 +85,12 @@ async def create_link(project_id: UUID, link_data: schemas.Link):
await link.update_suspend(link_data["suspend"])
try:
for node in link_data["nodes"]:
await link.add_node(project.get_node(node["node_id"]),
node.get("adapter_number", 0),
node.get("port_number", 0),
label=node.get("label"))
await link.add_node(
project.get_node(node["node_id"]),
node.get("adapter_number", 0),
node.get("port_number", 0),
label=node.get("label"),
)
except ControllerError as e:
await project.delete_link(link.id)
raise e
@@ -103,9 +106,7 @@ async def get_filters(link: Link = Depends(dep_link)):
return link.available_filters()
@router.get("/{link_id}",
response_model=schemas.Link,
response_model_exclude_unset=True)
@router.get("/{link_id}", response_model=schemas.Link, response_model_exclude_unset=True)
async def get_link(link: Link = Depends(dep_link)):
"""
Return a link.
@@ -114,9 +115,7 @@ async def get_link(link: Link = Depends(dep_link)):
return link.__json__()
@router.put("/{link_id}",
response_model=schemas.Link,
response_model_exclude_unset=True)
@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)):
"""
Update a link.
@@ -132,8 +131,7 @@ async def update_link(link_data: schemas.Link, link: Link = Depends(dep_link)):
return link.__json__()
@router.delete("/{link_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{link_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_link(project_id: UUID, link: Link = Depends(dep_link)):
"""
Delete a link.
@@ -143,8 +141,7 @@ async def delete_link(project_id: UUID, link: Link = Depends(dep_link)):
await project.delete_link(link.id)
@router.post("/{link_id}/reset",
response_model=schemas.Link)
@router.post("/{link_id}/reset", response_model=schemas.Link)
async def reset_link(link: Link = Depends(dep_link)):
"""
Reset a link.
@@ -154,21 +151,20 @@ async def reset_link(link: Link = Depends(dep_link)):
return link.__json__()
@router.post("/{link_id}/capture/start",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Link)
@router.post("/{link_id}/capture/start", status_code=status.HTTP_201_CREATED, response_model=schemas.Link)
async def start_capture(capture_data: dict, link: Link = Depends(dep_link)):
"""
Start packet capture on the link.
"""
await link.start_capture(data_link_type=capture_data.get("data_link_type", "DLT_EN10MB"),
capture_file_name=capture_data.get("capture_file_name"))
await link.start_capture(
data_link_type=capture_data.get("data_link_type", "DLT_EN10MB"),
capture_file_name=capture_data.get("capture_file_name"),
)
return link.__json__()
@router.post("/{link_id}/capture/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{link_id}/capture/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_capture(link: Link = Depends(dep_link)):
"""
Stop packet capture on the link.
@@ -189,8 +185,8 @@ async def stream_pcap(request: Request, link: Link = Depends(dep_link)):
compute = link.compute
pcap_streaming_url = link.pcap_streaming_url()
headers = multidict.MultiDict(request.headers)
headers['Host'] = compute.host
headers['Router-Host'] = request.client.host
headers["Host"] = compute.host
headers["Router-Host"] = request.client.host
body = await request.body()
async def compute_pcap_stream():
+48 -65
View File
@@ -36,6 +36,7 @@ from gns3server.controller.controller_error import ControllerForbiddenError
from gns3server import schemas
import logging
log = logging.getLogger(__name__)
node_locks = {}
@@ -75,9 +76,7 @@ class NodeConcurrency(APIRoute):
return custom_route_handler
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or node"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or node"}}
router = APIRouter(route_class=NodeConcurrency, responses=responses)
@@ -100,11 +99,15 @@ async def dep_node(node_id: UUID, project: Project = Depends(dep_project)):
return node
@router.post("",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Node,
responses={404: {"model": schemas.ErrorMessage, "description": "Could not find project"},
409: {"model": schemas.ErrorMessage, "description": "Could not create node"}})
@router.post(
"",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Node,
responses={
404: {"model": schemas.ErrorMessage, "description": "Could not find project"},
409: {"model": schemas.ErrorMessage, "description": "Could not create node"},
},
)
async def create_node(node_data: schemas.Node, project: Project = Depends(dep_project)):
"""
Create a new node.
@@ -113,16 +116,11 @@ async def create_node(node_data: schemas.Node, project: Project = Depends(dep_pr
controller = Controller.instance()
compute = controller.get_compute(str(node_data.compute_id))
node_data = jsonable_encoder(node_data, exclude_unset=True)
node = await project.add_node(compute,
node_data.pop("name"),
node_data.pop("node_id", None),
**node_data)
node = await project.add_node(compute, node_data.pop("name"), node_data.pop("node_id", None), **node_data)
return node.__json__()
@router.get("",
response_model=List[schemas.Node],
response_model_exclude_unset=True)
@router.get("", response_model=List[schemas.Node], response_model_exclude_unset=True)
async def get_nodes(project: Project = Depends(dep_project)):
"""
Return all nodes belonging to a given project.
@@ -131,8 +129,7 @@ async def get_nodes(project: Project = Depends(dep_project)):
return [v.__json__() for v in project.nodes.values()]
@router.post("/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_all_nodes(project: Project = Depends(dep_project)):
"""
Start all nodes belonging to a given project.
@@ -141,8 +138,7 @@ async def start_all_nodes(project: Project = Depends(dep_project)):
await project.start_all()
@router.post("/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_all_nodes(project: Project = Depends(dep_project)):
"""
Stop all nodes belonging to a given project.
@@ -151,8 +147,7 @@ async def stop_all_nodes(project: Project = Depends(dep_project)):
await project.stop_all()
@router.post("/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_all_nodes(project: Project = Depends(dep_project)):
"""
Suspend all nodes belonging to a given project.
@@ -161,8 +156,7 @@ async def suspend_all_nodes(project: Project = Depends(dep_project)):
await project.suspend_all()
@router.post("/reload",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_all_nodes(project: Project = Depends(dep_project)):
"""
Reload all nodes belonging to a given project.
@@ -172,8 +166,7 @@ async def reload_all_nodes(project: Project = Depends(dep_project)):
await project.start_all()
@router.get("/{node_id}",
response_model=schemas.Node)
@router.get("/{node_id}", response_model=schemas.Node)
def get_node(node: Node = Depends(dep_node)):
"""
Return a node from a given project.
@@ -182,9 +175,7 @@ def get_node(node: Node = Depends(dep_node)):
return node.__json__()
@router.put("/{node_id}",
response_model=schemas.Node,
response_model_exclude_unset=True)
@router.put("/{node_id}", response_model=schemas.Node, response_model_exclude_unset=True)
async def update_node(node_data: schemas.NodeUpdate, node: Node = Depends(dep_node)):
"""
Update a node.
@@ -201,10 +192,11 @@ async def update_node(node_data: schemas.NodeUpdate, node: Node = Depends(dep_no
return node.__json__()
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT,
responses={**responses,
409: {"model": schemas.ErrorMessage, "description": "Cannot delete node"}})
@router.delete(
"/{node_id}",
status_code=status.HTTP_204_NO_CONTENT,
responses={**responses, 409: {"model": schemas.ErrorMessage, "description": "Cannot delete node"}},
)
async def delete_node(node_id: UUID, project: Project = Depends(dep_project)):
"""
Delete a node from a project.
@@ -213,23 +205,17 @@ async def delete_node(node_id: UUID, project: Project = Depends(dep_project)):
await project.delete_node(str(node_id))
@router.post("/{node_id}/duplicate",
response_model=schemas.Node,
status_code=status.HTTP_201_CREATED)
@router.post("/{node_id}/duplicate", response_model=schemas.Node, status_code=status.HTTP_201_CREATED)
async def duplicate_node(duplicate_data: schemas.NodeDuplicate, node: Node = Depends(dep_node)):
"""
Duplicate a node.
"""
new_node = await node.project.duplicate_node(node,
duplicate_data.x,
duplicate_data.y,
duplicate_data.z)
new_node = await node.project.duplicate_node(node, duplicate_data.x, duplicate_data.y, duplicate_data.z)
return new_node.__json__()
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_node(start_data: dict, node: Node = Depends(dep_node)):
"""
Start a node.
@@ -238,8 +224,7 @@ async def start_node(start_data: dict, node: Node = Depends(dep_node)):
await node.start(data=start_data)
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_node(node: Node = Depends(dep_node)):
"""
Stop a node.
@@ -248,8 +233,7 @@ async def stop_node(node: Node = Depends(dep_node)):
await node.stop()
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_node(node: Node = Depends(dep_node)):
"""
Suspend a node.
@@ -258,8 +242,7 @@ async def suspend_node(node: Node = Depends(dep_node)):
await node.suspend()
@router.post("/{node_id}/reload",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_node(node: Node = Depends(dep_node)):
"""
Reload a node.
@@ -268,9 +251,7 @@ async def reload_node(node: Node = Depends(dep_node)):
await node.reload()
@router.get("/{node_id}/links",
response_model=List[schemas.Link],
response_model_exclude_unset=True)
@router.get("/{node_id}/links", response_model=List[schemas.Link], response_model_exclude_unset=True)
async def get_node_links(node: Node = Depends(dep_node)):
"""
Return all the links connected to a node.
@@ -300,8 +281,7 @@ async def idlepc_proposals(node: Node = Depends(dep_node)):
return await node.dynamips_idlepc_proposals()
@router.post("/{node_id}/resize_disk",
status_code=status.HTTP_201_CREATED)
@router.post("/{node_id}/resize_disk", status_code=status.HTTP_201_CREATED)
async def resize_disk(resize_data: dict, node: Node = Depends(dep_node)):
"""
Resize a disk image.
@@ -328,8 +308,7 @@ async def get_file(file_path: str, node: Node = Depends(dep_node)):
return Response(res.body, media_type="application/octet-stream")
@router.post("/{node_id}/files/{file_path:path}",
status_code=status.HTTP_201_CREATED)
@router.post("/{node_id}/files/{file_path:path}", status_code=status.HTTP_201_CREATED)
async def post_file(file_path: str, request: Request, node: Node = Depends(dep_node)):
"""
Write a file in the node directory.
@@ -344,7 +323,7 @@ async def post_file(file_path: str, request: Request, node: Node = Depends(dep_n
node_type = node.node_type
path = f"/project-files/{node_type}/{node.id}/{path}"
data = await request.body() #FIXME: are we handling timeout or large files correctly?
data = await request.body() # FIXME: are we handling timeout or large files correctly?
await node.compute.http_query("POST", f"/projects/{node.project.id}/files{path}", data=data, timeout=None, raw=True)
@@ -357,9 +336,13 @@ async def ws_console(websocket: WebSocket, node: Node = Depends(dep_node)):
compute = node.compute
await websocket.accept()
log.info(f"New client {websocket.client.host}:{websocket.client.port} has connected to controller console WebSocket")
ws_console_compute_url = f"ws://{compute.host}:{compute.port}/v3/compute/projects/" \
f"{node.project.id}/{node.node_type}/nodes/{node.id}/console/ws"
log.info(
f"New client {websocket.client.host}:{websocket.client.port} has connected to controller console WebSocket"
)
ws_console_compute_url = (
f"ws://{compute.host}:{compute.port}/v3/compute/projects/"
f"{node.project.id}/{node.node_type}/nodes/{node.id}/console/ws"
)
async def ws_receive(ws_console_compute):
"""
@@ -373,8 +356,10 @@ async def ws_console(websocket: WebSocket, node: Node = Depends(dep_node)):
await ws_console_compute.send_str(data)
except WebSocketDisconnect:
await ws_console_compute.close()
log.info(f"Client {websocket.client.host}:{websocket.client.port} has disconnected from controller"
f" console WebSocket")
log.info(
f"Client {websocket.client.host}:{websocket.client.port} has disconnected from controller"
f" console WebSocket"
)
try:
# receive WebSocket data from compute console WebSocket and forward to client.
@@ -391,8 +376,7 @@ async def ws_console(websocket: WebSocket, node: Node = Depends(dep_node)):
log.error(f"Client error received when forwarding to compute console WebSocket: {e}")
@router.post("/console/reset",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console_all_nodes(project: Project = Depends(dep_project)):
"""
Reset console for all nodes belonging to the project.
@@ -401,8 +385,7 @@ async def reset_console_all_nodes(project: Project = Depends(dep_project)):
await project.reset_console_all()
@router.post("/{node_id}/console/reset",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def console_reset(node: Node = Depends(dep_node)):
await node.post("/console/reset")#, request.json)
await node.post("/console/reset") # , request.json)
@@ -25,6 +25,7 @@ from websockets.exceptions import ConnectionClosed, WebSocketException
from gns3server.controller import Controller
import logging
log = logging.getLogger(__name__)
router = APIRouter()
+62 -66
View File
@@ -26,6 +26,7 @@ import aiofiles
import time
import logging
log = logging.getLogger()
from fastapi import APIRouter, Depends, Request, Body, HTTPException, status, WebSocket, WebSocketDisconnect
@@ -45,9 +46,7 @@ from gns3server.controller.export_project import export_project as export_contro
from gns3server.utils.asyncio import aiozipstream
from gns3server.config import Config
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project"}}
router = APIRouter(responses=responses)
@@ -64,9 +63,7 @@ def dep_project(project_id: UUID):
CHUNK_SIZE = 1024 * 8 # 8KB
@router.get("",
response_model=List[schemas.Project],
response_model_exclude_unset=True)
@router.get("", response_model=List[schemas.Project], response_model_exclude_unset=True)
def get_projects():
"""
Return all projects.
@@ -76,11 +73,13 @@ def get_projects():
return [p.__json__() for p in controller.projects.values()]
@router.post("",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
response_model_exclude_unset=True,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create project"}})
@router.post(
"",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
response_model_exclude_unset=True,
responses={409: {"model": schemas.ErrorMessage, "description": "Could not create project"}},
)
async def create_project(project_data: schemas.ProjectCreate):
"""
Create a new project.
@@ -91,8 +90,7 @@ async def create_project(project_data: schemas.ProjectCreate):
return project.__json__()
@router.get("/{project_id}",
response_model=schemas.Project)
@router.get("/{project_id}", response_model=schemas.Project)
def get_project(project: Project = Depends(dep_project)):
"""
Return a project.
@@ -101,9 +99,7 @@ def get_project(project: Project = Depends(dep_project)):
return project.__json__()
@router.put("/{project_id}",
response_model=schemas.Project,
response_model_exclude_unset=True)
@router.put("/{project_id}", response_model=schemas.Project, response_model_exclude_unset=True)
async def update_project(project_data: schemas.ProjectUpdate, project: Project = Depends(dep_project)):
"""
Update a project.
@@ -113,8 +109,7 @@ async def update_project(project_data: schemas.ProjectUpdate, project: Project =
return project.__json__()
@router.delete("/{project_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{project_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_project(project: Project = Depends(dep_project)):
"""
Delete a project.
@@ -134,12 +129,11 @@ def get_project_stats(project: Project = Depends(dep_project)):
return project.stats()
@router.post("/{project_id}/close",
status_code=status.HTTP_204_NO_CONTENT,
responses={
**responses,
409: {"model": schemas.ErrorMessage, "description": "Could not close project"}
})
@router.post(
"/{project_id}/close",
status_code=status.HTTP_204_NO_CONTENT,
responses={**responses, 409: {"model": schemas.ErrorMessage, "description": "Could not close project"}},
)
async def close_project(project: Project = Depends(dep_project)):
"""
Close a project.
@@ -148,13 +142,12 @@ async def close_project(project: Project = Depends(dep_project)):
await project.close()
@router.post("/{project_id}/open",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
responses={
**responses,
409: {"model": schemas.ErrorMessage, "description": "Could not open project"}
})
@router.post(
"/{project_id}/open",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
responses={**responses, 409: {"model": schemas.ErrorMessage, "description": "Could not open project"}},
)
async def open_project(project: Project = Depends(dep_project)):
"""
Open a project.
@@ -164,13 +157,12 @@ async def open_project(project: Project = Depends(dep_project)):
return project.__json__()
@router.post("/load",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
responses={
**responses,
409: {"model": schemas.ErrorMessage, "description": "Could not load project"}
})
@router.post(
"/load",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
responses={**responses, 409: {"model": schemas.ErrorMessage, "description": "Could not load project"}},
)
async def load_project(path: str = Body(..., embed=True)):
"""
Load a project (local server only).
@@ -181,7 +173,9 @@ async def load_project(path: str = Body(..., embed=True)):
if Config.instance().settings.Server.local is False:
log.error(f"Cannot load '{dot_gns3_file}' because the server has not been started with the '--local' parameter")
raise ControllerForbiddenError("Cannot load project when server is not local")
project = await controller.load_project(dot_gns3_file,)
project = await controller.load_project(
dot_gns3_file,
)
return project.__json__()
@@ -248,11 +242,13 @@ async def notification_ws(project_id: UUID, websocket: WebSocket):
@router.get("/{project_id}/export")
async def export_project(project: Project = Depends(dep_project),
include_snapshots: bool = False,
include_images: bool = False,
reset_mac_addresses: bool = False,
compression: str = "zip"):
async def export_project(
project: Project = Depends(dep_project),
include_snapshots: bool = False,
include_images: bool = False,
reset_mac_addresses: bool = False,
compression: str = "zip",
):
"""
Export a project as a portable archive.
"""
@@ -275,12 +271,14 @@ async def export_project(project: Project = Depends(dep_project),
async def streamer():
with tempfile.TemporaryDirectory(dir=working_dir) as tmpdir:
with aiozipstream.ZipFile(compression=compression) as zstream:
await export_controller_project(zstream,
project,
tmpdir,
include_snapshots=include_snapshots,
include_images=include_images,
reset_mac_addresses=reset_mac_addresses)
await export_controller_project(
zstream,
project,
tmpdir,
include_snapshots=include_snapshots,
include_images=include_images,
reset_mac_addresses=reset_mac_addresses,
)
async for chunk in zstream:
yield chunk
@@ -295,9 +293,7 @@ async def export_project(project: Project = Depends(dep_project),
return StreamingResponse(streamer(), media_type="application/gns3project", headers=headers)
@router.post("/{project_id}/import",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project)
@router.post("/{project_id}/import", status_code=status.HTTP_201_CREATED, response_model=schemas.Project)
async def import_project(project_id: UUID, request: Request, path: Optional[Path] = None, name: Optional[str] = None):
"""
Import a project from a portable archive.
@@ -318,7 +314,7 @@ async def import_project(project_id: UUID, request: Request, path: Optional[Path
working_dir = controller.projects_directory()
with tempfile.TemporaryDirectory(dir=working_dir) as tmpdir:
temp_project_path = os.path.join(tmpdir, "project.zip")
async with aiofiles.open(temp_project_path, 'wb') as f:
async with aiofiles.open(temp_project_path, "wb") as f:
async for chunk in request.stream():
await f.write(chunk)
with open(temp_project_path, "rb") as f:
@@ -330,13 +326,12 @@ async def import_project(project_id: UUID, request: Request, path: Optional[Path
return project.__json__()
@router.post("/{project_id}/duplicate",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
responses={
**responses,
409: {"model": schemas.ErrorMessage, "description": "Could not duplicate project"}
})
@router.post(
"/{project_id}/duplicate",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
responses={**responses, 409: {"model": schemas.ErrorMessage, "description": "Could not duplicate project"}},
)
async def duplicate_project(project_data: schemas.ProjectDuplicate, project: Project = Depends(dep_project)):
"""
Duplicate a project.
@@ -350,7 +345,9 @@ async def duplicate_project(project_data: schemas.ProjectDuplicate, project: Pro
location = None
reset_mac_addresses = project_data.reset_mac_addresses
new_project = await project.duplicate(name=project_data.name, location=location, reset_mac_addresses=reset_mac_addresses)
new_project = await project.duplicate(
name=project_data.name, location=location, reset_mac_addresses=reset_mac_addresses
)
return new_project.__json__()
@@ -360,7 +357,7 @@ async def get_file(file_path: str, project: Project = Depends(dep_project)):
Return a file from a project.
"""
path = os.path.normpath(file_path).strip('/')
path = os.path.normpath(file_path).strip("/")
# Raise error if user try to escape
if path[0] == ".":
@@ -373,8 +370,7 @@ async def get_file(file_path: str, project: Project = Depends(dep_project)):
return FileResponse(path, media_type="application/octet-stream")
@router.post("/{project_id}/files/{file_path:path}",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{project_id}/files/{file_path:path}", status_code=status.HTTP_204_NO_CONTENT)
async def write_file(file_path: str, request: Request, project: Project = Depends(dep_project)):
"""
Write a file from a project.
@@ -389,7 +385,7 @@ async def write_file(file_path: str, request: Request, project: Project = Depend
path = os.path.join(project.path, path)
try:
async with aiofiles.open(path, 'wb+') as f:
async with aiofiles.open(path, "wb+") as f:
async for chunk in request.stream():
await f.write(chunk)
except FileNotFoundError:
+6 -14
View File
@@ -20,6 +20,7 @@ API routes for snapshots.
"""
import logging
log = logging.getLogger()
from fastapi import APIRouter, Depends, status
@@ -30,9 +31,7 @@ from gns3server.controller.project import Project
from gns3server import schemas
from gns3server.controller import Controller
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find project or snapshot"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or snapshot"}}
router = APIRouter(responses=responses)
@@ -46,9 +45,7 @@ def dep_project(project_id: UUID):
return project
@router.post("",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Snapshot)
@router.post("", status_code=status.HTTP_201_CREATED, response_model=schemas.Snapshot)
async def create_snapshot(snapshot_data: schemas.SnapshotCreate, project: Project = Depends(dep_project)):
"""
Create a new snapshot of a project.
@@ -58,9 +55,7 @@ async def create_snapshot(snapshot_data: schemas.SnapshotCreate, project: Projec
return snapshot.__json__()
@router.get("",
response_model=List[schemas.Snapshot],
response_model_exclude_unset=True)
@router.get("", response_model=List[schemas.Snapshot], response_model_exclude_unset=True)
def get_snapshots(project: Project = Depends(dep_project)):
"""
Return all snapshots belonging to a given project.
@@ -70,8 +65,7 @@ def get_snapshots(project: Project = Depends(dep_project)):
return [s.__json__() for s in sorted(snapshots, key=lambda s: (s.created_at, s.name))]
@router.delete("/{snapshot_id}",
status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{snapshot_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_snapshot(snapshot_id: UUID, project: Project = Depends(dep_project)):
"""
Delete a snapshot.
@@ -80,9 +74,7 @@ async def delete_snapshot(snapshot_id: UUID, project: Project = Depends(dep_proj
await project.delete_snapshot(str(snapshot_id))
@router.post("/{snapshot_id}/restore",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project)
@router.post("/{snapshot_id}/restore", status_code=status.HTTP_201_CREATED, response_model=schemas.Project)
async def restore_snapshot(snapshot_id: UUID, project: Project = Depends(dep_project)):
"""
Restore a snapshot.
+10 -7
View File
@@ -29,6 +29,7 @@ from gns3server import schemas
from gns3server.controller.controller_error import ControllerError, ControllerNotFoundError
import logging
log = logging.getLogger(__name__)
@@ -42,8 +43,9 @@ def get_symbols():
return controller.symbols.list()
@router.get("/{symbol_id:path}/raw",
responses={404: {"model": schemas.ErrorMessage, "description": "Could not find symbol"}})
@router.get(
"/{symbol_id:path}/raw", responses={404: {"model": schemas.ErrorMessage, "description": "Could not find symbol"}}
)
async def get_symbol(symbol_id: str):
"""
Download a symbol file.
@@ -57,8 +59,10 @@ async def get_symbol(symbol_id: str):
return ControllerNotFoundError(f"Could not get symbol file: {e}")
@router.get("/{symbol_id:path}/dimensions",
responses={404: {"model": schemas.ErrorMessage, "description": "Could not find symbol"}})
@router.get(
"/{symbol_id:path}/dimensions",
responses={404: {"model": schemas.ErrorMessage, "description": "Could not find symbol"}},
)
async def get_symbol_dimensions(symbol_id: str):
"""
Get a symbol dimensions.
@@ -67,14 +71,13 @@ async def get_symbol_dimensions(symbol_id: str):
controller = Controller.instance()
try:
width, height, _ = controller.symbols.get_size(symbol_id)
symbol_dimensions = {'width': width, 'height': height}
symbol_dimensions = {"width": width, "height": height}
return symbol_dimensions
except (KeyError, OSError, ValueError) as e:
return ControllerNotFoundError(f"Could not get symbol file: {e}")
@router.post("/{symbol_id:path}/raw",
status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{symbol_id:path}/raw", status_code=status.HTTP_204_NO_CONTENT)
async def upload_symbol(symbol_id: str, request: Request):
"""
Upload a symbol file.
+35 -43
View File
@@ -22,6 +22,7 @@ import hashlib
import json
import logging
log = logging.getLogger(__name__)
from fastapi import APIRouter, Request, Response, HTTPException, Depends, status
@@ -34,17 +35,15 @@ from gns3server.db.repositories.templates import TemplatesRepository
from gns3server.services.templates import TemplatesService
from .dependencies.database import get_repository
responses = {
404: {"model": schemas.ErrorMessage, "description": "Could not find template"}
}
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find template"}}
router = APIRouter(responses=responses)
@router.post("/templates", response_model=schemas.Template, status_code=status.HTTP_201_CREATED)
async def create_template(
template_create: schemas.TemplateCreate,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository))
template_create: schemas.TemplateCreate,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
) -> dict:
"""
Create a new template.
@@ -53,14 +52,12 @@ async def create_template(
return await TemplatesService(templates_repo).create_template(template_create)
@router.get("/templates/{template_id}",
response_model=schemas.Template,
response_model_exclude_unset=True)
@router.get("/templates/{template_id}", response_model=schemas.Template, response_model_exclude_unset=True)
async def get_template(
template_id: UUID,
request: Request,
response: Response,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository))
template_id: UUID,
request: Request,
response: Response,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
) -> dict:
"""
Return a template.
@@ -77,13 +74,11 @@ async def get_template(
return template
@router.put("/templates/{template_id}",
response_model=schemas.Template,
response_model_exclude_unset=True)
@router.put("/templates/{template_id}", response_model=schemas.Template, response_model_exclude_unset=True)
async def update_template(
template_id: UUID,
template_update: schemas.TemplateUpdate,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository))
template_id: UUID,
template_update: schemas.TemplateUpdate,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
) -> dict:
"""
Update a template.
@@ -92,11 +87,12 @@ async def update_template(
return await TemplatesService(templates_repo).update_template(template_id, template_update)
@router.delete("/templates/{template_id}",
status_code=status.HTTP_204_NO_CONTENT,)
@router.delete(
"/templates/{template_id}",
status_code=status.HTTP_204_NO_CONTENT,
)
async def delete_template(
template_id: UUID,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository))
template_id: UUID, templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository))
) -> None:
"""
Delete a template.
@@ -105,11 +101,9 @@ async def delete_template(
await TemplatesService(templates_repo).delete_template(template_id)
@router.get("/templates",
response_model=List[schemas.Template],
response_model_exclude_unset=True)
@router.get("/templates", response_model=List[schemas.Template], response_model_exclude_unset=True)
async def get_templates(
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository))
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
) -> List[dict]:
"""
Return all templates.
@@ -118,12 +112,9 @@ async def get_templates(
return await TemplatesService(templates_repo).get_templates()
@router.post("/templates/{template_id}/duplicate",
response_model=schemas.Template,
status_code=status.HTTP_201_CREATED)
@router.post("/templates/{template_id}/duplicate", response_model=schemas.Template, status_code=status.HTTP_201_CREATED)
async def duplicate_template(
template_id: UUID,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository))
template_id: UUID, templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository))
) -> dict:
"""
Duplicate a template.
@@ -132,15 +123,17 @@ async def duplicate_template(
return await TemplatesService(templates_repo).duplicate_template(template_id)
@router.post("/projects/{project_id}/templates/{template_id}",
response_model=schemas.Node,
status_code=status.HTTP_201_CREATED,
responses={404: {"model": schemas.ErrorMessage, "description": "Could not find project or template"}})
@router.post(
"/projects/{project_id}/templates/{template_id}",
response_model=schemas.Node,
status_code=status.HTTP_201_CREATED,
responses={404: {"model": schemas.ErrorMessage, "description": "Could not find project or template"}},
)
async def create_node_from_template(
project_id: UUID,
template_id: UUID,
template_usage: schemas.TemplateUsage,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository))
project_id: UUID,
template_id: UUID,
template_usage: schemas.TemplateUsage,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
) -> schemas.Node:
"""
Create a new node from a template.
@@ -149,8 +142,7 @@ async def create_node_from_template(
template = TemplatesService(templates_repo).get_template(template_id)
controller = Controller.instance()
project = controller.get_project(str(project_id))
node = await project.add_node_from_template(template,
x=template_usage.x,
y=template_usage.y,
compute_id=template_usage.compute_id)
node = await project.add_node_from_template(
template, x=template_usage.x, y=template_usage.y, compute_id=template_usage.compute_id
)
return node.__json__()
+17 -16
View File
@@ -28,7 +28,7 @@ from gns3server import schemas
from gns3server.controller.controller_error import (
ControllerBadRequestError,
ControllerNotFoundError,
ControllerUnauthorizedError
ControllerUnauthorizedError,
)
from gns3server.db.repositories.users import UsersRepository
@@ -38,6 +38,7 @@ from .dependencies.authentication import get_current_active_user
from .dependencies.database import get_repository
import logging
log = logging.getLogger(__name__)
router = APIRouter()
@@ -54,8 +55,7 @@ async def get_users(users_repo: UsersRepository = Depends(get_repository(UsersRe
@router.post("", response_model=schemas.User, status_code=status.HTTP_201_CREATED)
async def create_user(
user_create: schemas.UserCreate,
users_repo: UsersRepository = Depends(get_repository(UsersRepository))
user_create: schemas.UserCreate, users_repo: UsersRepository = Depends(get_repository(UsersRepository))
) -> schemas.User:
"""
Create a new user.
@@ -72,8 +72,7 @@ async def create_user(
@router.get("/{user_id}", response_model=schemas.User)
async def get_user(
user_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository))
user_id: UUID, users_repo: UsersRepository = Depends(get_repository(UsersRepository))
) -> schemas.User:
"""
Get an user.
@@ -87,9 +86,9 @@ async def get_user(
@router.put("/{user_id}", response_model=schemas.User)
async def update_user(
user_id: UUID,
user_update: schemas.UserUpdate,
users_repo: UsersRepository = Depends(get_repository(UsersRepository))
user_id: UUID,
user_update: schemas.UserUpdate,
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
) -> schemas.User:
"""
Update an user.
@@ -103,9 +102,9 @@ async def update_user(
@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_user(
user_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
current_user: schemas.User = Depends(get_current_active_user)
user_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
current_user: schemas.User = Depends(get_current_active_user),
) -> None:
"""
Delete an user.
@@ -121,8 +120,8 @@ async def delete_user(
@router.post("/login", response_model=schemas.Token)
async def login(
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
form_data: OAuth2PasswordRequestForm = Depends()
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
form_data: OAuth2PasswordRequestForm = Depends(),
) -> schemas.Token:
"""
User login.
@@ -130,9 +129,11 @@ async def login(
user = await users_repo.authenticate_user(username=form_data.username, password=form_data.password)
if not user:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="Authentication was unsuccessful.",
headers={"WWW-Authenticate": "Bearer"})
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Authentication was unsuccessful.",
headers={"WWW-Authenticate": "Bearer"},
)
token = schemas.Token(access_token=auth_service.create_access_token(user.username), token_type="bearer")
return token
+7 -13
View File
@@ -21,7 +21,7 @@ from fastapi.responses import RedirectResponse, HTMLResponse, FileResponse
from fastapi.templating import Jinja2Templates
from gns3server.version import __version__
from gns3server.utils.get_resource import get_resource
from gns3server.utils.get_resource import get_resource
router = APIRouter()
templates = Jinja2Templates(directory=os.path.join("gns3server", "templates"))
@@ -33,24 +33,18 @@ async def root():
return RedirectResponse("/static/web-ui/bundled", status_code=308) # permanent redirect
@router.get("/debug",
response_class=HTMLResponse,
deprecated=True)
@router.get("/debug", response_class=HTMLResponse, deprecated=True)
def debug(request: Request):
kwargs = {"request": request,
"gns3_version": __version__,
"gns3_host": request.client.host}
kwargs = {"request": request, "gns3_version": __version__, "gns3_host": request.client.host}
return templates.TemplateResponse("index.html", kwargs)
@router.get("/static/web-ui/{file_path:path}",
description="Web user interface"
)
@router.get("/static/web-ui/{file_path:path}", description="Web user interface")
async def web_ui(file_path: str):
file_path = os.path.normpath(file_path).strip("/")
file_path = os.path.join('static', 'web-ui', file_path)
file_path = os.path.join("static", "web-ui", file_path)
# Raise error if user try to escape
if file_path[0] == ".":
@@ -59,13 +53,13 @@ async def web_ui(file_path: str):
static = get_resource(file_path)
if static is None or not os.path.exists(static):
static = get_resource(os.path.join('static', 'web-ui', 'index.html'))
static = get_resource(os.path.join("static", "web-ui", "index.html"))
# guesstype prefers to have text/html type than application/javascript
# which results with warnings in Firefox 66 on Windows
# Ref. gns3-server#1559
_, ext = os.path.splitext(static)
mimetype = ext == '.js' and 'application/javascript' or None
mimetype = ext == ".js" and "application/javascript" or None
return FileResponse(static, media_type=mimetype)
+10 -11
View File
@@ -33,7 +33,7 @@ from gns3server.controller.controller_error import (
ControllerBadRequestError,
ControllerTimeoutError,
ControllerForbiddenError,
ControllerUnauthorizedError
ControllerUnauthorizedError,
)
from gns3server.api.routes import controller, index
@@ -42,15 +42,14 @@ from gns3server.core import tasks
from gns3server.version import __version__
import logging
log = logging.getLogger(__name__)
def get_application() -> FastAPI:
application = FastAPI(
title="GNS3 controller API",
description="This page describes the public controller API for GNS3",
version="v3"
title="GNS3 controller API", description="This page describes the public controller API for GNS3", version="v3"
)
origins = [
@@ -61,16 +60,16 @@ def get_application() -> FastAPI:
"http://127.0.0.1:3080",
"http://localhost:3080",
"http://gns3.github.io",
"https://gns3.github.io"
"https://gns3.github.io",
]
application.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
application.add_event_handler("startup", tasks.create_startup_handler(application))
application.add_event_handler("shutdown", tasks.create_shutdown_handler(application))