1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-11-12 19:38:57 +00:00

Merge branch '3.0' into iou-user-loader-libraries

This commit is contained in:
Jeremy Grossmann 2022-07-20 16:44:48 +02:00 committed by GitHub
commit da626d334f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 528 additions and 402 deletions

View File

@ -67,7 +67,7 @@ compute_api.state.controller_host = None
@compute_api.exception_handler(ComputeError)
async def controller_error_handler(request: Request, exc: ComputeError):
async def compute_error_handler(request: Request, exc: ComputeError):
log.error(f"Compute error: {exc}")
return JSONResponse(
status_code=409,
@ -76,7 +76,7 @@ async def controller_error_handler(request: Request, exc: ComputeError):
@compute_api.exception_handler(ComputeTimeoutError)
async def controller_timeout_error_handler(request: Request, exc: ComputeTimeoutError):
async def compute_timeout_error_handler(request: Request, exc: ComputeTimeoutError):
log.error(f"Compute timeout error: {exc}")
return JSONResponse(
status_code=408,
@ -85,7 +85,7 @@ async def controller_timeout_error_handler(request: Request, exc: ComputeTimeout
@compute_api.exception_handler(ComputeUnauthorizedError)
async def controller_unauthorized_error_handler(request: Request, exc: ComputeUnauthorizedError):
async def compute_unauthorized_error_handler(request: Request, exc: ComputeUnauthorizedError):
log.error(f"Compute unauthorized error: {exc}")
return JSONResponse(
status_code=401,
@ -94,7 +94,7 @@ async def controller_unauthorized_error_handler(request: Request, exc: ComputeUn
@compute_api.exception_handler(ComputeForbiddenError)
async def controller_forbidden_error_handler(request: Request, exc: ComputeForbiddenError):
async def compute_forbidden_error_handler(request: Request, exc: ComputeForbiddenError):
log.error(f"Compute forbidden error: {exc}")
return JSONResponse(
status_code=403,
@ -103,7 +103,7 @@ async def controller_forbidden_error_handler(request: Request, exc: ComputeForbi
@compute_api.exception_handler(ComputeNotFoundError)
async def controller_not_found_error_handler(request: Request, exc: ComputeNotFoundError):
async def compute_not_found_error_handler(request: Request, exc: ComputeNotFoundError):
log.error(f"Compute not found error: {exc}")
return JSONResponse(
status_code=404,
@ -112,7 +112,7 @@ async def controller_not_found_error_handler(request: Request, exc: ComputeNotFo
@compute_api.exception_handler(GNS3VMError)
async def controller_error_handler(request: Request, exc: GNS3VMError):
async def compute_gns3vm_error_handler(request: Request, exc: GNS3VMError):
log.error(f"Compute GNS3 VM error: {exc}")
return JSONResponse(
status_code=409,

View File

@ -109,43 +109,42 @@ async def update_atm_switch(
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_atm_switch_node(node: ATMSwitch = Depends(dep_node)) -> Response:
async def delete_atm_switch_node(node: ATMSwitch = Depends(dep_node)) -> None:
"""
Delete an ATM switch node.
"""
await Dynamips.instance().delete_node(node.id)
return Response(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)) -> Response:
def start_atm_switch(node: ATMSwitch = Depends(dep_node)) -> None:
"""
Start an ATM switch node.
This endpoint results in no action since ATM switch nodes are always on.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
def stop_atm_switch(node: ATMSwitch = Depends(dep_node)) -> Response:
def stop_atm_switch(node: ATMSwitch = Depends(dep_node)) -> None:
"""
Stop an ATM switch node.
This endpoint results in no action since ATM switch nodes are always on.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
def suspend_atm_switch(node: ATMSwitch = Depends(dep_node)) -> Response:
def suspend_atm_switch(node: ATMSwitch = Depends(dep_node)) -> None:
"""
Suspend an ATM switch node.
This endpoint results in no action since ATM switch nodes are always on.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post(
@ -171,7 +170,7 @@ async def create_nio(
@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)) -> Response:
async def delete_nio(adapter_number: int, port_number: int, node: ATMSwitch = Depends(dep_node)) -> None:
"""
Remove a NIO (Network Input/Output) from the node.
The adapter number on the switch is always 0.
@ -179,7 +178,6 @@ async def delete_nio(adapter_number: int, port_number: int, node: ATMSwitch = De
nio = await node.remove_nio(port_number)
await nio.delete()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -209,14 +207,13 @@ async def stop_capture(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: ATMSwitch = Depends(dep_node)
) -> Response:
) -> None:
"""
Stop a packet capture on the node.
The adapter number on the switch is always 0.
"""
await node.stop_capture(port_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream")

View File

@ -99,43 +99,41 @@ def update_cloud(node_data: schemas.CloudUpdate, node: Cloud = Depends(dep_node)
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_cloud(node: Cloud = Depends(dep_node)) -> Response:
async def delete_cloud(node: Cloud = Depends(dep_node)) -> None:
"""
Delete a cloud node.
"""
await Builtin.instance().delete_node(node.id)
return Response(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)) -> Response:
async def start_cloud(node: Cloud = Depends(dep_node)) -> None:
"""
Start a cloud node.
"""
await node.start()
return Response(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)) -> Response:
async def stop_cloud(node: Cloud = Depends(dep_node)) -> None:
"""
Stop a cloud node.
This endpoint results in no action since cloud nodes cannot be stopped.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_cloud(node: Cloud = Depends(dep_node)) -> Response:
async def suspend_cloud(node: Cloud = Depends(dep_node)) -> None:
"""
Suspend a cloud node.
This endpoint results in no action since cloud nodes cannot be suspended.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post(
@ -190,14 +188,13 @@ async def delete_cloud_nio(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: Cloud = Depends(dep_node)
) -> Response:
) -> None:
"""
Remove a NIO (Network Input/Output) from the node.
The adapter number on the cloud is always 0.
"""
await node.remove_nio(port_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -226,14 +223,13 @@ async def stop_cloud_capture(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: Cloud = Depends(dep_node)
) -> Response:
) -> None:
"""
Stop a packet capture on the node.
The adapter number on the cloud is always 0.
"""
await node.stop_capture(port_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/pcap")

View File

@ -132,73 +132,66 @@ async def update_docker_node(node_data: schemas.DockerUpdate, node: DockerVM = D
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_docker_node(node: DockerVM = Depends(dep_node)) -> Response:
async def start_docker_node(node: DockerVM = Depends(dep_node)) -> None:
"""
Start a Docker node.
"""
await node.start()
return Response(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)) -> Response:
async def stop_docker_node(node: DockerVM = Depends(dep_node)) -> None:
"""
Stop a Docker node.
"""
await node.stop()
return Response(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)) -> Response:
async def suspend_docker_node(node: DockerVM = Depends(dep_node)) -> None:
"""
Suspend a Docker node.
"""
await node.pause()
return Response(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)) -> Response:
async def reload_docker_node(node: DockerVM = Depends(dep_node)) -> None:
"""
Reload a Docker node.
"""
await node.restart()
return Response(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)) -> Response:
async def pause_docker_node(node: DockerVM = Depends(dep_node)) -> None:
"""
Pause a Docker node.
"""
await node.pause()
return Response(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)) -> Response:
async def unpause_docker_node(node: DockerVM = Depends(dep_node)) -> None:
"""
Unpause a Docker node.
"""
await node.unpause()
return Response(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)) -> Response:
async def delete_docker_node(node: DockerVM = Depends(dep_node)) -> None:
"""
Delete a Docker node.
"""
await node.delete()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/duplicate", response_model=schemas.Docker, status_code=status.HTTP_201_CREATED)
@ -257,14 +250,13 @@ async def delete_docker_node_nio(
adapter_number: int,
port_number: int,
node: DockerVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Delete a NIO (Network Input/Output) from the node.
The port number on the Docker node is always 0.
"""
await node.adapter_remove_nio_binding(adapter_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -292,14 +284,13 @@ async def stop_docker_node_capture(
adapter_number: int,
port_number: int,
node: DockerVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Stop a packet capture on the node.
The port number on the Docker node is always 0.
"""
await node.stop_capture(adapter_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream")
@ -328,7 +319,6 @@ async def console_ws(websocket: WebSocket, node: DockerVM = Depends(dep_node)) -
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: DockerVM = Depends(dep_node)) -> Response:
async def reset_console(node: DockerVM = Depends(dep_node)) -> None:
await node.reset_console()
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -19,7 +19,6 @@ API routes for Dynamips nodes.
"""
import os
import sys
from fastapi import APIRouter, WebSocket, Depends, Response, status
from fastapi.encoders import jsonable_encoder
@ -29,7 +28,6 @@ from uuid import UUID
from gns3server.compute.dynamips import Dynamips
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"}}
@ -105,17 +103,16 @@ async def update_router(node_data: schemas.DynamipsUpdate, node: Router = Depend
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_router(node: Router = Depends(dep_node)) -> Response:
async def delete_router(node: Router = Depends(dep_node)) -> None:
"""
Delete a Dynamips router.
"""
await Dynamips.instance().delete_node(node.id)
return Response(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)) -> Response:
async def start_router(node: Router = Depends(dep_node)) -> None:
"""
Start a Dynamips router.
"""
@ -125,44 +122,39 @@ async def start_router(node: Router = Depends(dep_node)) -> Response:
except GeneratorExit:
pass
await node.start()
return Response(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)) -> Response:
async def stop_router(node: Router = Depends(dep_node)) -> None:
"""
Stop a Dynamips router.
"""
await node.stop()
return Response(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)) -> Response:
async def suspend_router(node: Router = Depends(dep_node)) -> None:
await node.suspend()
return Response(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)) -> Response:
async def resume_router(node: Router = Depends(dep_node)) -> None:
"""
Resume a suspended Dynamips router.
"""
await node.resume()
return Response(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)) -> Response:
async def reload_router(node: Router = Depends(dep_node)) -> None:
"""
Reload a suspended Dynamips router.
"""
await node.reload()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
@ -208,14 +200,13 @@ async def update_nio(
@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)) -> Response:
async def delete_nio(adapter_number: int, port_number: int, node: Router = Depends(dep_node)) -> None:
"""
Delete a NIO (Network Input/Output) from the node.
"""
nio = await node.slot_remove_nio_binding(adapter_number, port_number)
await nio.delete()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -237,13 +228,12 @@ async def start_capture(
@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)) -> Response:
async def stop_capture(adapter_number: int, port_number: int, node: Router = Depends(dep_node)) -> None:
"""
Stop a packet capture on the node.
"""
await node.stop_capture(adapter_number, port_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream")
@ -301,7 +291,6 @@ async def console_ws(websocket: WebSocket, node: Router = Depends(dep_node)) ->
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: Router = Depends(dep_node)) -> Response:
async def reset_console(node: Router = Depends(dep_node)) -> None:
await node.reset_console()
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -108,43 +108,42 @@ async def update_ethernet_hub(
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_ethernet_hub(node: EthernetHub = Depends(dep_node)) -> Response:
async def delete_ethernet_hub(node: EthernetHub = Depends(dep_node)) -> None:
"""
Delete an Ethernet hub.
"""
await Dynamips.instance().delete_node(node.id)
return Response(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)) -> Response:
def start_ethernet_hub(node: EthernetHub = Depends(dep_node)) -> None:
"""
Start an Ethernet hub.
This endpoint results in no action since Ethernet hub nodes are always on.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
def stop_ethernet_hub(node: EthernetHub = Depends(dep_node)) -> Response:
def stop_ethernet_hub(node: EthernetHub = Depends(dep_node)) -> None:
"""
Stop an Ethernet hub.
This endpoint results in no action since Ethernet hub nodes are always on.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
def suspend_ethernet_hub(node: EthernetHub = Depends(dep_node)) -> Response:
def suspend_ethernet_hub(node: EthernetHub = Depends(dep_node)) -> None:
"""
Suspend an Ethernet hub.
This endpoint results in no action since Ethernet hub nodes are always on.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post(
@ -175,7 +174,7 @@ async def delete_nio(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: EthernetHub = Depends(dep_node)
) -> Response:
) -> None:
"""
Delete a NIO (Network Input/Output) from the node.
The adapter number on the hub is always 0.
@ -183,7 +182,6 @@ async def delete_nio(
nio = await node.remove_nio(port_number)
await nio.delete()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -212,14 +210,13 @@ async def stop_capture(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: EthernetHub = Depends(dep_node)
) -> Response:
) -> None:
"""
Stop a packet capture on the node.
The adapter number on the hub is always 0.
"""
await node.stop_capture(port_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream")

View File

@ -112,43 +112,42 @@ async def update_ethernet_switch(
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_ethernet_switch(node: EthernetSwitch = Depends(dep_node)) -> Response:
async def delete_ethernet_switch(node: EthernetSwitch = Depends(dep_node)) -> None:
"""
Delete an Ethernet switch.
"""
await Dynamips.instance().delete_node(node.id)
return Response(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)) -> Response:
def start_ethernet_switch(node: EthernetSwitch = Depends(dep_node)) -> None:
"""
Start an Ethernet switch.
This endpoint results in no action since Ethernet switch nodes are always on.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
def stop_ethernet_switch(node: EthernetSwitch = Depends(dep_node)) -> Response:
def stop_ethernet_switch(node: EthernetSwitch = Depends(dep_node)) -> None:
"""
Stop an Ethernet switch.
This endpoint results in no action since Ethernet switch nodes are always on.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
def suspend_ethernet_switch(node: EthernetSwitch = Depends(dep_node)) -> Response:
def suspend_ethernet_switch(node: EthernetSwitch = Depends(dep_node)) -> None:
"""
Suspend an Ethernet switch.
This endpoint results in no action since Ethernet switch nodes are always on.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post(
@ -175,7 +174,7 @@ async def delete_nio(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: EthernetSwitch = Depends(dep_node)
) -> Response:
) -> None:
"""
Delete a NIO (Network Input/Output) from the node.
The adapter number on the switch is always 0.
@ -183,7 +182,6 @@ async def delete_nio(
nio = await node.remove_nio(port_number)
await nio.delete()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -212,14 +210,13 @@ async def stop_capture(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: EthernetSwitch = Depends(dep_node)
) -> Response:
) -> None:
"""
Stop a packet capture on the node.
The adapter number on the switch is always 0.
"""
await node.stop_capture(port_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream")

View File

@ -112,43 +112,42 @@ async def update_frame_relay_switch(
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)) -> Response:
async def delete_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)) -> None:
"""
Delete a Frame Relay switch node.
"""
await Dynamips.instance().delete_node(node.id)
return Response(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)) -> Response:
def start_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)) -> None:
"""
Start a Frame Relay switch node.
This endpoint results in no action since Frame Relay switch nodes are always on.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
def stop_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)) -> Response:
def stop_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)) -> None:
"""
Stop a Frame Relay switch node.
This endpoint results in no action since Frame Relay switch nodes are always on.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
def suspend_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)) -> Response:
def suspend_frame_relay_switch(node: FrameRelaySwitch = Depends(dep_node)) -> None:
"""
Suspend a Frame Relay switch node.
This endpoint results in no action since Frame Relay switch nodes are always on.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post(
@ -179,7 +178,7 @@ async def delete_nio(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: FrameRelaySwitch = Depends(dep_node)
) -> Response:
) -> None:
"""
Remove a NIO (Network Input/Output) from the node.
The adapter number on the switch is always 0.
@ -187,7 +186,6 @@ async def delete_nio(
nio = await node.remove_nio(port_number)
await nio.delete()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -216,14 +214,13 @@ async def stop_capture(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: FrameRelaySwitch = Depends(dep_node)
) -> Response:
) -> None:
"""
Stop a packet capture on the node.
The adapter number on the switch is always 0.
"""
await node.stop_capture(port_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream")

View File

@ -54,14 +54,13 @@ async def get_dynamips_images() -> List[str]:
@router.post("/dynamips/images/{filename:path}", status_code=status.HTTP_204_NO_CONTENT)
async def upload_dynamips_image(filename: str, request: Request) -> Response:
async def upload_dynamips_image(filename: str, request: Request) -> None:
"""
Upload a Dynamips IOS image.
"""
dynamips_manager = Dynamips.instance()
await dynamips_manager.write_image(urllib.parse.unquote(filename), request.stream())
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/dynamips/images/{filename:path}")
@ -96,14 +95,13 @@ async def get_iou_images() -> List[str]:
@router.post("/iou/images/{filename:path}", status_code=status.HTTP_204_NO_CONTENT)
async def upload_iou_image(filename: str, request: Request) -> Response:
async def upload_iou_image(filename: str, request: Request) -> None:
"""
Upload an IOU image.
"""
iou_manager = IOU.instance()
await iou_manager.write_image(urllib.parse.unquote(filename), request.stream())
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/iou/images/{filename:path}")
@ -134,11 +132,10 @@ async def get_qemu_images() -> List[str]:
@router.post("/qemu/images/{filename:path}", status_code=status.HTTP_204_NO_CONTENT)
async def upload_qemu_image(filename: str, request: Request) -> Response:
async def upload_qemu_image(filename: str, request: Request) -> None:
qemu_manager = Qemu.instance()
await qemu_manager.write_image(urllib.parse.unquote(filename), request.stream())
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/qemu/images/{filename:path}")

View File

@ -20,7 +20,7 @@ API routes for IOU nodes.
import os
from fastapi import APIRouter, WebSocket, Depends, Body, Response, status
from fastapi import APIRouter, WebSocket, Depends, Body, status
from fastapi.encoders import jsonable_encoder
from fastapi.responses import StreamingResponse
from typing import Union
@ -113,13 +113,12 @@ async def update_iou_node(node_data: schemas.IOUUpdate, node: IOUVM = Depends(de
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_iou_node(node: IOUVM = Depends(dep_node)) -> Response:
async def delete_iou_node(node: IOUVM = Depends(dep_node)) -> None:
"""
Delete an IOU node.
"""
await IOU.instance().delete_node(node.id)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/duplicate", response_model=schemas.IOU, status_code=status.HTTP_201_CREATED)
@ -136,7 +135,7 @@ async def duplicate_iou_node(
@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)) -> Response:
async def start_iou_node(start_data: schemas.IOUStart, node: IOUVM = Depends(dep_node)) -> None:
"""
Start an IOU node.
"""
@ -147,37 +146,34 @@ async def start_iou_node(start_data: schemas.IOUStart, node: IOUVM = Depends(dep
setattr(node, name, value)
await node.start()
return Response(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)) -> Response:
async def stop_iou_node(node: IOUVM = Depends(dep_node)) -> None:
"""
Stop an IOU node.
"""
await node.stop()
return Response(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)) -> Response:
def suspend_iou_node(node: IOUVM = Depends(dep_node)) -> None:
"""
Suspend an IOU node.
Does nothing since IOU doesn't support being suspended.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post("/{node_id}/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_iou_node(node: IOUVM = Depends(dep_node)) -> Response:
async def reload_iou_node(node: IOUVM = Depends(dep_node)) -> None:
"""
Reload an IOU node.
"""
await node.reload()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
@ -223,13 +219,12 @@ async def update_iou_node_nio(
@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)) -> Response:
async def delete_iou_node_nio(adapter_number: int, port_number: int, node: IOUVM = Depends(dep_node)) -> None:
"""
Delete a NIO (Network Input/Output) from the node.
"""
await node.adapter_remove_nio_binding(adapter_number, port_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -251,13 +246,12 @@ async def start_iou_node_capture(
@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)) -> Response:
async def stop_iou_node_capture(adapter_number: int, port_number: int, node: IOUVM = Depends(dep_node)) -> None:
"""
Stop a packet capture on the node.
"""
await node.stop_capture(adapter_number, port_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream")
@ -285,7 +279,6 @@ async def console_ws(websocket: WebSocket, node: IOUVM = Depends(dep_node)) -> N
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: IOUVM = Depends(dep_node)) -> Response:
async def reset_console(node: IOUVM = Depends(dep_node)) -> None:
await node.reset_console()
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -94,43 +94,41 @@ def update_nat_node(node_data: schemas.NATUpdate, node: Nat = Depends(dep_node))
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_nat_node(node: Nat = Depends(dep_node)) -> Response:
async def delete_nat_node(node: Nat = Depends(dep_node)) -> None:
"""
Delete a cloud node.
"""
await Builtin.instance().delete_node(node.id)
return Response(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)) -> Response:
async def start_nat_node(node: Nat = Depends(dep_node)) -> None:
"""
Start a NAT node.
"""
await node.start()
return Response(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)) -> Response:
async def stop_nat_node(node: Nat = Depends(dep_node)) -> None:
"""
Stop a NAT node.
This endpoint results in no action since cloud nodes cannot be stopped.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_nat_node(node: Nat = Depends(dep_node)) -> Response:
async def suspend_nat_node(node: Nat = Depends(dep_node)) -> None:
"""
Suspend a NAT node.
This endpoint results in no action since NAT nodes cannot be suspended.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post(
@ -185,14 +183,13 @@ async def delete_nat_node_nio(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: Nat = Depends(dep_node)
) -> Response:
) -> None:
"""
Remove a NIO (Network Input/Output) from the node.
The adapter number on the cloud is always 0.
"""
await node.remove_nio(port_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -221,14 +218,13 @@ async def stop_nat_node_capture(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: Nat = Depends(dep_node)
) -> Response:
) -> None:
"""
Stop a packet capture on the node.
The adapter number on the cloud is always 0.
"""
await node.stop_capture(port_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream")

View File

@ -103,7 +103,7 @@ def get_compute_project(project: Project = Depends(dep_project)) -> schemas.Proj
@router.post("/projects/{project_id}/close", status_code=status.HTTP_204_NO_CONTENT)
async def close_compute_project(project: Project = Depends(dep_project)) -> Response:
async def close_compute_project(project: Project = Depends(dep_project)) -> None:
"""
Close a project on the compute.
"""
@ -118,18 +118,16 @@ async def close_compute_project(project: Project = Depends(dep_project)) -> Resp
pass
else:
log.warning("Skip project closing, another client is listening for project notifications")
return Response(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)) -> Response:
async def delete_compute_project(project: Project = Depends(dep_project)) -> None:
"""
Delete project from the compute.
"""
await project.delete()
ProjectManager.instance().remove_project(project.id)
return Response(status_code=status.HTTP_204_NO_CONTENT)
# @Route.get(
# r"/projects/{project_id}/notifications",
@ -219,7 +217,7 @@ async def write_compute_project_file(
file_path: str,
request: Request,
project: Project = Depends(dep_project)
) -> Response:
) -> None:
file_path = urllib.parse.unquote(file_path)
path = os.path.normpath(file_path)
@ -243,5 +241,3 @@ async def write_compute_project_file(
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
except PermissionError:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -104,13 +104,12 @@ async def update_qemu_node(node_data: schemas.QemuUpdate, node: QemuVM = Depends
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_qemu_node(node: QemuVM = Depends(dep_node)) -> Response:
async def delete_qemu_node(node: QemuVM = Depends(dep_node)) -> None:
"""
Delete a Qemu node.
"""
await Qemu.instance().delete_node(node.id)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/duplicate", response_model=schemas.Qemu, status_code=status.HTTP_201_CREATED)
@ -134,14 +133,13 @@ async def create_qemu_disk_image(
disk_name: str,
disk_data: schemas.QemuDiskImageCreate,
node: QemuVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Create a Qemu disk image.
"""
options = jsonable_encoder(disk_data, exclude_unset=True)
await node.create_disk_image(disk_name, options)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.put(
@ -152,14 +150,13 @@ async def update_qemu_disk_image(
disk_name: str,
disk_data: schemas.QemuDiskImageUpdate,
node: QemuVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Update a Qemu disk image.
"""
if disk_data.extend:
await node.resize_disk_image(disk_name, disk_data.extend)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
@ -169,63 +166,57 @@ async def update_qemu_disk_image(
async def delete_qemu_disk_image(
disk_name: str,
node: QemuVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Delete a Qemu disk image.
"""
node.delete_disk_image(disk_name)
return Response(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)) -> Response:
async def start_qemu_node(node: QemuVM = Depends(dep_node)) -> None:
"""
Start a Qemu node.
"""
await node.start()
return Response(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)) -> Response:
async def stop_qemu_node(node: QemuVM = Depends(dep_node)) -> None:
"""
Stop a Qemu node.
"""
await node.stop()
return Response(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)) -> Response:
async def reload_qemu_node(node: QemuVM = Depends(dep_node)) -> None:
"""
Reload a Qemu node.
"""
await node.reload()
return Response(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)) -> Response:
async def suspend_qemu_node(node: QemuVM = Depends(dep_node)) -> None:
"""
Suspend a Qemu node.
"""
await node.suspend()
return Response(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)) -> Response:
async def resume_qemu_node(node: QemuVM = Depends(dep_node)) -> None:
"""
Resume a Qemu node.
"""
await node.resume()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
@ -281,14 +272,13 @@ async def delete_qemu_node_nio(
adapter_number: int,
port_number: int = Path(..., ge=0, le=0),
node: QemuVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Delete a NIO (Network Input/Output) from the node.
The port number on the Qemu node is always 0.
"""
await node.adapter_remove_nio_binding(adapter_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -316,14 +306,13 @@ async def stop_qemu_node_capture(
adapter_number: int,
port_number: int = Path(..., ge=0, le=0),
node: QemuVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Stop a packet capture on the node.
The port number on the Qemu node is always 0.
"""
await node.stop_capture(adapter_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream")
@ -351,7 +340,6 @@ async def console_ws(websocket: WebSocket, node: QemuVM = Depends(dep_node)) ->
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: QemuVM = Depends(dep_node)) -> Response:
async def reset_console(node: QemuVM = Depends(dep_node)) -> None:
await node.reset_console()
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -137,63 +137,57 @@ async def update_virtualbox_node(
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)) -> Response:
async def delete_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)) -> None:
"""
Delete a VirtualBox node.
"""
await VirtualBox.instance().delete_node(node.id)
return Response(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)) -> Response:
async def start_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)) -> None:
"""
Start a VirtualBox node.
"""
await node.start()
return Response(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)) -> Response:
async def stop_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)) -> None:
"""
Stop a VirtualBox node.
"""
await node.stop()
return Response(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)) -> Response:
async def suspend_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)) -> None:
"""
Suspend a VirtualBox node.
"""
await node.suspend()
return Response(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)) -> Response:
async def resume_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)) -> None:
"""
Resume a VirtualBox node.
"""
await node.resume()
return Response(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)) -> Response:
async def reload_virtualbox_node(node: VirtualBoxVM = Depends(dep_node)) -> None:
"""
Reload a VirtualBox node.
"""
await node.reload()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
@ -249,14 +243,13 @@ async def delete_virtualbox_node_nio(
adapter_number: int,
port_number: int = Path(..., ge=0, le=0),
node: VirtualBoxVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Delete a NIO (Network Input/Output) from the node.
The port number on the VirtualBox node is always 0.
"""
await node.adapter_remove_nio_binding(adapter_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -284,14 +277,13 @@ async def stop_virtualbox_node_capture(
adapter_number: int,
port_number: int = Path(..., ge=0, le=0),
node: VirtualBoxVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Stop a packet capture on the node.
The port number on the VirtualBox node is always 0.
"""
await node.stop_capture(adapter_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream")
@ -320,7 +312,7 @@ async def console_ws(websocket: WebSocket, node: VirtualBoxVM = Depends(dep_node
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: VirtualBoxVM = Depends(dep_node)) -> Response:
async def reset_console(node: VirtualBoxVM = Depends(dep_node)) -> None:
await node.reset_console()
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -103,63 +103,57 @@ def update_vmware_node(node_data: schemas.VMwareUpdate, node: VMwareVM = Depends
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_vmware_node(node: VMwareVM = Depends(dep_node)) -> Response:
async def delete_vmware_node(node: VMwareVM = Depends(dep_node)) -> None:
"""
Delete a VMware node.
"""
await VMware.instance().delete_node(node.id)
return Response(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)) -> Response:
async def start_vmware_node(node: VMwareVM = Depends(dep_node)) -> None:
"""
Start a VMware node.
"""
await node.start()
return Response(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)) -> Response:
async def stop_vmware_node(node: VMwareVM = Depends(dep_node)) -> None:
"""
Stop a VMware node.
"""
await node.stop()
return Response(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)) -> Response:
async def suspend_vmware_node(node: VMwareVM = Depends(dep_node)) -> None:
"""
Suspend a VMware node.
"""
await node.suspend()
return Response(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)) -> Response:
async def resume_vmware_node(node: VMwareVM = Depends(dep_node)) -> None:
"""
Resume a VMware node.
"""
await node.resume()
return Response(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)) -> Response:
async def reload_vmware_node(node: VMwareVM = Depends(dep_node)) -> None:
"""
Reload a VMware node.
"""
await node.reload()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
@ -213,14 +207,13 @@ async def delete_vmware_node_nio(
adapter_number: int,
port_number: int = Path(..., ge=0, le=0),
node: VMwareVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Delete a NIO (Network Input/Output) from the node.
The port number on the VMware node is always 0.
"""
await node.adapter_remove_nio_binding(adapter_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -248,14 +241,13 @@ async def stop_vmware_node_capture(
adapter_number: int,
port_number: int = Path(..., ge=0, le=0),
node: VMwareVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Stop a packet capture on the node.
The port number on the VMware node is always 0.
"""
await node.stop_capture(adapter_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream")
@ -297,7 +289,7 @@ async def console_ws(websocket: WebSocket, node: VMwareVM = Depends(dep_node)) -
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console(node: VMwareVM = Depends(dep_node)) -> Response:
async def reset_console(node: VMwareVM = Depends(dep_node)) -> None:
await node.reset_console()
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -93,13 +93,12 @@ def update_vpcs_node(node_data: schemas.VPCSUpdate, node: VPCSVM = Depends(dep_n
@router.delete("/{node_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_vpcs_node(node: VPCSVM = Depends(dep_node)) -> Response:
async def delete_vpcs_node(node: VPCSVM = Depends(dep_node)) -> None:
"""
Delete a VPCS node.
"""
await VPCS.instance().delete_node(node.id)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/duplicate", response_model=schemas.VPCS, status_code=status.HTTP_201_CREATED)
@ -115,43 +114,40 @@ async def duplicate_vpcs_node(
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_vpcs_node(node: VPCSVM = Depends(dep_node)) -> Response:
async def start_vpcs_node(node: VPCSVM = Depends(dep_node)) -> None:
"""
Start a VPCS node.
"""
await node.start()
return Response(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)) -> Response:
async def stop_vpcs_node(node: VPCSVM = Depends(dep_node)) -> None:
"""
Stop a VPCS node.
"""
await node.stop()
return Response(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)) -> Response:
async def suspend_vpcs_node(node: VPCSVM = Depends(dep_node)) -> None:
"""
Suspend a VPCS node.
Does nothing, suspend is not supported by VPCS.
"""
return Response(status_code=status.HTTP_204_NO_CONTENT)
pass
@router.post("/{node_id}/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_vpcs_node(node: VPCSVM = Depends(dep_node)) -> Response:
async def reload_vpcs_node(node: VPCSVM = Depends(dep_node)) -> None:
"""
Reload a VPCS node.
"""
await node.reload()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
@ -206,14 +202,13 @@ async def delete_vpcs_node_nio(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: VPCSVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Delete a NIO (Network Input/Output) from the node.
The adapter number on the VPCS node is always 0.
"""
await node.port_remove_nio_binding(port_number)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/start")
@ -242,21 +237,19 @@ async def stop_vpcs_node_capture(
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
node: VPCSVM = Depends(dep_node)
) -> Response:
) -> None:
"""
Stop a packet capture on the node.
The adapter number on the VPCS node is always 0.
"""
await node.stop_capture(port_number)
return Response(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)) -> Response:
async def reset_console(node: VPCSVM = Depends(dep_node)) -> None:
await node.reset_console()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/adapters/{adapter_number}/ports/{port_number}/capture/stream")

View File

@ -106,7 +106,7 @@ async def install_appliance(
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
current_user: schemas.User = Depends(get_current_active_user),
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> Response:
) -> None:
"""
Install an appliance.
"""
@ -120,4 +120,3 @@ async def install_appliance(
rbac_repo,
current_user
)
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -57,7 +57,7 @@ async def create_compute(
@router.post("/{compute_id}/connect", status_code=status.HTTP_204_NO_CONTENT)
async def connect_compute(compute_id: Union[str, UUID]) -> Response:
async def connect_compute(compute_id: Union[str, UUID]) -> None:
"""
Connect to compute on the controller.
"""
@ -65,7 +65,6 @@ async def connect_compute(compute_id: Union[str, UUID]) -> Response:
compute = Controller.instance().get_compute(str(compute_id))
if not compute.connected:
await compute.connect(report_failed_connection=True)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{compute_id}", response_model=schemas.Compute, response_model_exclude_unset=True)
@ -106,13 +105,12 @@ async def update_compute(
@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))
) -> Response:
) -> None:
"""
Delete a compute from the controller.
"""
await ComputesService(computes_repo).delete_compute(compute_id)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{compute_id}/docker/images", response_model=List[schemas.ComputeDockerImage])

View File

@ -83,13 +83,12 @@ def check_version(version: schemas.Version) -> dict:
dependencies=[Depends(get_current_active_user)],
status_code=status.HTTP_204_NO_CONTENT,
)
async def reload() -> Response:
async def reload() -> None:
"""
Reload the controller
"""
await Controller.instance().reload()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
@ -98,7 +97,7 @@ async def reload() -> Response:
status_code=status.HTTP_204_NO_CONTENT,
responses={403: {"model": schemas.ErrorMessage, "description": "Server shutdown not allowed"}},
)
async def shutdown() -> Response:
async def shutdown() -> None:
"""
Shutdown the server
"""
@ -126,7 +125,6 @@ async def shutdown() -> Response:
# then shutdown the server itself
os.kill(os.getpid(), signal.SIGTERM)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get(

View File

@ -32,7 +32,7 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/v3/users/login", auto_error=Fals
async def get_user_from_token(
bearer_token: str = Depends(oauth2_scheme),
user_repo: UsersRepository = Depends(get_repository(UsersRepository)),
token: Optional[str] = None,
token: Optional[str] = Query(None, include_in_schema=False)
) -> schemas.User:
if bearer_token:

View File

@ -76,11 +76,10 @@ async def update_drawing(project_id: UUID, drawing_id: UUID, drawing_data: schem
@router.delete("/{drawing_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_drawing(project_id: UUID, drawing_id: UUID) -> Response:
async def delete_drawing(project_id: UUID, drawing_id: UUID) -> None:
"""
Delete a drawing.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
await project.delete_drawing(str(drawing_id))
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -113,7 +113,7 @@ async def update_user_group(
async def delete_user_group(
user_group_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
) -> Response:
) -> None:
"""
Delete an user group
"""
@ -129,8 +129,6 @@ async def delete_user_group(
if not success:
raise ControllerError(f"User group '{user_group_id}' could not be deleted")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{user_group_id}/members", response_model=List[schemas.User])
async def get_user_group_members(
@ -152,7 +150,7 @@ async def add_member_to_group(
user_group_id: UUID,
user_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository))
) -> Response:
) -> None:
"""
Add member to an user group.
"""
@ -165,8 +163,6 @@ async def add_member_to_group(
if not user_group:
raise ControllerNotFoundError(f"User group '{user_group_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
"/{user_group_id}/members/{user_id}",
@ -176,7 +172,7 @@ async def remove_member_from_group(
user_group_id: UUID,
user_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
) -> Response:
) -> None:
"""
Remove member from an user group.
"""
@ -189,8 +185,6 @@ async def remove_member_from_group(
if not user_group:
raise ControllerNotFoundError(f"User group '{user_group_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{user_group_id}/roles", response_model=List[schemas.Role])
async def get_user_group_roles(
@ -226,8 +220,6 @@ async def add_role_to_group(
if not user_group:
raise ControllerNotFoundError(f"User group '{user_group_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
"/{user_group_id}/roles/{role_id}",
@ -238,7 +230,7 @@ async def remove_role_from_group(
role_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> Response:
) -> None:
"""
Remove role from an user group.
"""
@ -250,5 +242,3 @@ async def remove_role_from_group(
user_group = await users_repo.remove_role_from_user_group(user_group_id, role)
if not user_group:
raise ControllerNotFoundError(f"User group '{user_group_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -129,7 +129,7 @@ async def get_image(
async def delete_image(
image_path: str,
images_repo: ImagesRepository = Depends(get_repository(ImagesRepository)),
) -> Response:
) -> None:
"""
Delete an image.
"""
@ -159,16 +159,13 @@ async def delete_image(
if not success:
raise ControllerError(f"Image '{image_path}' could not be deleted")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/prune", status_code=status.HTTP_204_NO_CONTENT)
async def prune_images(
images_repo: ImagesRepository = Depends(get_repository(ImagesRepository)),
) -> Response:
) -> None:
"""
Prune images not attached to any template.
"""
await images_repo.prune_images()
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -136,14 +136,13 @@ async def update_link(link_data: schemas.LinkUpdate, link: Link = Depends(dep_li
@router.delete("/{link_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_link(project_id: UUID, link: Link = Depends(dep_link)) -> Response:
async def delete_link(project_id: UUID, link: Link = Depends(dep_link)) -> None:
"""
Delete a link.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
await project.delete_link(link.id)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{link_id}/reset", response_model=schemas.Link)
@ -170,13 +169,12 @@ async def start_capture(capture_data: dict, link: Link = Depends(dep_link)) -> s
@router.post("/{link_id}/capture/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_capture(link: Link = Depends(dep_link)) -> Response:
async def stop_capture(link: Link = Depends(dep_link)) -> None:
"""
Stop packet capture on the link.
"""
await link.stop_capture()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{link_id}/capture/stream")

View File

@ -130,44 +130,40 @@ async def get_nodes(project: Project = Depends(dep_project)) -> List[schemas.Nod
@router.post("/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_all_nodes(project: Project = Depends(dep_project)) -> Response:
async def start_all_nodes(project: Project = Depends(dep_project)) -> None:
"""
Start all nodes belonging to a given project.
"""
await project.start_all()
return Response(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)) -> Response:
async def stop_all_nodes(project: Project = Depends(dep_project)) -> None:
"""
Stop all nodes belonging to a given project.
"""
await project.stop_all()
return Response(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)) -> Response:
async def suspend_all_nodes(project: Project = Depends(dep_project)) -> None:
"""
Suspend all nodes belonging to a given project.
"""
await project.suspend_all()
return Response(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)) -> Response:
async def reload_all_nodes(project: Project = Depends(dep_project)) -> None:
"""
Reload all nodes belonging to a given project.
"""
await project.stop_all()
await project.start_all()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}", response_model=schemas.Node)
@ -201,13 +197,12 @@ async def update_node(node_data: schemas.NodeUpdate, node: Node = Depends(dep_no
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)) -> Response:
async def delete_node(node_id: UUID, project: Project = Depends(dep_project)) -> None:
"""
Delete a node from a project.
"""
await project.delete_node(str(node_id))
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/duplicate", response_model=schemas.Node, status_code=status.HTTP_201_CREATED)
@ -221,65 +216,59 @@ async def duplicate_node(duplicate_data: schemas.NodeDuplicate, node: Node = Dep
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_node(start_data: dict, node: Node = Depends(dep_node)) -> Response:
async def start_node(start_data: dict, node: Node = Depends(dep_node)) -> None:
"""
Start a node.
"""
await node.start(data=start_data)
return Response(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)) -> Response:
async def stop_node(node: Node = Depends(dep_node)) -> None:
"""
Stop a node.
"""
await node.stop()
return Response(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)) -> Response:
async def suspend_node(node: Node = Depends(dep_node)) -> None:
"""
Suspend a node.
"""
await node.suspend()
return Response(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)) -> Response:
async def reload_node(node: Node = Depends(dep_node)) -> None:
"""
Reload a node.
"""
await node.reload()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/isolate", status_code=status.HTTP_204_NO_CONTENT)
async def isolate_node(node: Node = Depends(dep_node)) -> Response:
async def isolate_node(node: Node = Depends(dep_node)) -> None:
"""
Isolate a node (suspend all attached links).
"""
for link in node.links:
await link.update_suspend(True)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/unisolate", status_code=status.HTTP_204_NO_CONTENT)
async def unisolate_node(node: Node = Depends(dep_node)) -> Response:
async def unisolate_node(node: Node = Depends(dep_node)) -> None:
"""
Un-isolate a node (resume all attached suspended links).
"""
for link in node.links:
await link.update_suspend(False)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/links", response_model=List[schemas.Link], response_model_exclude_unset=True)
@ -321,7 +310,7 @@ async def create_disk_image(
disk_name: str,
disk_data: schemas.QemuDiskImageCreate,
node: Node = Depends(dep_node)
) -> Response:
) -> None:
"""
Create a Qemu disk image.
"""
@ -329,7 +318,6 @@ async def create_disk_image(
if node.node_type != "qemu":
raise ControllerBadRequestError("Creating a disk image is only supported on a Qemu node")
await node.post(f"/disk_image/{disk_name}", data=disk_data.dict(exclude_unset=True))
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.put("/{node_id}/qemu/disk_image/{disk_name}", status_code=status.HTTP_204_NO_CONTENT)
@ -337,7 +325,7 @@ async def update_disk_image(
disk_name: str,
disk_data: schemas.QemuDiskImageUpdate,
node: Node = Depends(dep_node)
) -> Response:
) -> None:
"""
Update a Qemu disk image.
"""
@ -345,14 +333,13 @@ async def update_disk_image(
if node.node_type != "qemu":
raise ControllerBadRequestError("Updating a disk image is only supported on a Qemu node")
await node.put(f"/disk_image/{disk_name}", data=disk_data.dict(exclude_unset=True))
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.delete("/{node_id}/qemu/disk_image/{disk_name}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_disk_image(
disk_name: str,
node: Node = Depends(dep_node)
) -> Response:
) -> None:
"""
Delete a Qemu disk image.
"""
@ -360,7 +347,6 @@ async def delete_disk_image(
if node.node_type != "qemu":
raise ControllerBadRequestError("Deleting a disk image is only supported on a Qemu node")
await node.delete(f"/disk_image/{disk_name}")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/files/{file_path:path}")
@ -451,17 +437,15 @@ async def ws_console(websocket: WebSocket, node: Node = Depends(dep_node)) -> No
@router.post("/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console_all_nodes(project: Project = Depends(dep_project)) -> Response:
async def reset_console_all_nodes(project: Project = Depends(dep_project)) -> None:
"""
Reset console for all nodes belonging to the project.
"""
await project.reset_console_all()
return Response(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)) -> Response:
async def console_reset(node: Node = Depends(dep_node)) -> None:
await node.post("/console/reset")
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -136,7 +136,7 @@ async def update_permission(
async def delete_permission(
permission_id: UUID,
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository)),
) -> Response:
) -> None:
"""
Delete a permission.
"""
@ -149,16 +149,13 @@ async def delete_permission(
if not success:
raise ControllerNotFoundError(f"Permission '{permission_id}' could not be deleted")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/prune", status_code=status.HTTP_204_NO_CONTENT)
async def prune_permissions(
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> Response:
) -> None:
"""
Prune orphaned permissions.
"""
await rbac_repo.prune_permissions()
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -141,7 +141,7 @@ async def update_project(
async def delete_project(
project: Project = Depends(dep_project),
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> Response:
) -> None:
"""
Delete a project.
"""
@ -150,7 +150,6 @@ async def delete_project(
await project.delete()
controller.remove_project(project)
await rbac_repo.delete_all_permissions_with_path(f"/projects/{project.id}")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{project_id}/stats")
@ -167,13 +166,12 @@ def get_project_stats(project: Project = Depends(dep_project)) -> dict:
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)) -> Response:
async def close_project(project: Project = Depends(dep_project)) -> None:
"""
Close a project.
"""
await project.close()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
@ -420,7 +418,7 @@ async def get_file(file_path: str, project: Project = Depends(dep_project)) -> F
@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)) -> Response:
async def write_file(file_path: str, request: Request, project: Project = Depends(dep_project)) -> None:
"""
Write a file to a project.
"""
@ -445,8 +443,6 @@ async def write_file(file_path: str, request: Request, project: Project = Depend
except OSError as e:
raise ControllerError(str(e))
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{project_id}/templates/{template_id}",

View File

@ -106,7 +106,7 @@ async def update_role(
async def delete_role(
role_id: UUID,
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository)),
) -> Response:
) -> None:
"""
Delete a role.
"""
@ -122,8 +122,6 @@ async def delete_role(
if not success:
raise ControllerError(f"Role '{role_id}' could not be deleted")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{role_id}/permissions", response_model=List[schemas.Permission])
async def get_role_permissions(
@ -145,7 +143,7 @@ async def add_permission_to_role(
role_id: UUID,
permission_id: UUID,
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> Response:
) -> None:
"""
Add a permission to a role.
"""
@ -158,8 +156,6 @@ async def add_permission_to_role(
if not role:
raise ControllerNotFoundError(f"Role '{role_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
"/{role_id}/permissions/{permission_id}",
@ -169,7 +165,7 @@ async def remove_permission_from_role(
role_id: UUID,
permission_id: UUID,
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository)),
) -> Response:
) -> None:
"""
Remove member from an user group.
"""
@ -181,5 +177,3 @@ async def remove_permission_from_role(
role = await rbac_repo.remove_permission_from_role(role_id, permission)
if not role:
raise ControllerNotFoundError(f"Role '{role_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -69,13 +69,12 @@ def get_snapshots(project: Project = Depends(dep_project)) -> List[schemas.Snaps
@router.delete("/{snapshot_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_snapshot(snapshot_id: UUID, project: Project = Depends(dep_project)) -> Response:
async def delete_snapshot(snapshot_id: UUID, project: Project = Depends(dep_project)) -> None:
"""
Delete a snapshot.
"""
await project.delete_snapshot(str(snapshot_id))
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{snapshot_id}/restore", status_code=status.HTTP_201_CREATED, response_model=schemas.Project)

View File

@ -95,7 +95,7 @@ def get_default_symbols() -> dict:
dependencies=[Depends(get_current_active_user)],
status_code=status.HTTP_204_NO_CONTENT
)
async def upload_symbol(symbol_id: str, request: Request) -> Response:
async def upload_symbol(symbol_id: str, request: Request) -> None:
"""
Upload a symbol file.
"""
@ -112,4 +112,3 @@ async def upload_symbol(symbol_id: str, request: Request) -> Response:
# Reset the symbol list
controller.symbols.list()
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -102,7 +102,7 @@ async def delete_template(
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
images_repo: RbacRepository = Depends(get_repository(ImagesRepository)),
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> Response:
) -> None:
"""
Delete a template.
"""
@ -111,7 +111,6 @@ async def delete_template(
await rbac_repo.delete_all_permissions_with_path(f"/templates/{template_id}")
if prune_images:
await images_repo.prune_images()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("", response_model=List[schemas.Template], response_model_exclude_unset=True)

View File

@ -194,7 +194,7 @@ async def update_user(
async def delete_user(
user_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
) -> Response:
) -> None:
"""
Delete an user.
"""
@ -210,8 +210,6 @@ async def delete_user(
if not success:
raise ControllerError(f"User '{user_id}' could not be deleted")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get(
"/{user_id}/groups",
@ -254,7 +252,7 @@ async def add_permission_to_user(
user_id: UUID,
permission_id: UUID,
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> Response:
) -> None:
"""
Add a permission to an user.
"""
@ -267,8 +265,6 @@ async def add_permission_to_user(
if not user:
raise ControllerNotFoundError(f"User '{user_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
"/{user_id}/permissions/{permission_id}",
@ -279,7 +275,7 @@ async def remove_permission_from_user(
user_id: UUID,
permission_id: UUID,
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository)),
) -> Response:
) -> None:
"""
Remove permission from an user.
"""
@ -291,5 +287,3 @@ async def remove_permission_from_user(
user = await rbac_repo.remove_permission_from_user(user_id, permission)
if not user:
raise ControllerNotFoundError(f"User '{user_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -4,7 +4,7 @@
"category": "multilayer_switch",
"description": "The ArubaOS-CX Simulation Software is a virtual platform to enable simulation of the ArubaOS-CX Network Operating System. Simulated networks can be created using many of the protocols in the ArubaOS-CX Operating system like OSPF, BGP (inc. EVPN). Key features like the Aruba Network Analytics Engine and the REST API can be simulated, providing a lightweight development platform to building the modern network.",
"vendor_name": "HPE Aruba",
"vendor_url": "arubanetworks.com",
"vendor_url": "https://www.arubanetworks.com",
"product_name": "ArubaOS-CX Simulation Software",
"registry_version": 4,
"status": "stable",
@ -30,6 +30,13 @@
"process_priority": "normal"
},
"images": [
{
"filename": "arubaoscx-disk-image-genericx86-p4-20220616193419.vmdk",
"version": "10.10.0002",
"md5sum": "ed031aeb6caf92adb408c7603d294fd4",
"filesize": 355858944,
"download_url": "https://asp.arubanetworks.com/"
},
{
"filename": "arubaoscx-disk-image-genericx86-p4-20220223012712.vmdk",
"version": "10.09.1000",
@ -88,6 +95,12 @@
}
],
"versions": [
{
"name": "10.10.0002",
"images": {
"hda_disk_image": "arubaoscx-disk-image-genericx86-p4-20220616193419.vmdk"
}
},
{
"name": "10.09.1000",
"images": {

View File

@ -4,7 +4,7 @@
"category": "firewall",
"description": "Aruba Virtual Gateways allow customers to bring their public cloud infrastructure to the SD-WAN fabric and facilitate connectivity between branches and the public cloud.",
"vendor_name": "HPE Aruba",
"vendor_url": "arubanetworks.com",
"vendor_url": "https://www.arubanetworks.com",
"documentation_url": "https://asp.arubanetworks.com/downloads;products=Aruba%20SD-WAN",
"product_name": "Aruba SD-WAN Virtual Gateway",
"product_url": "https://www.arubanetworks.com/products/networking/gateways-and-controllers/",

View File

@ -4,7 +4,7 @@
"category": "guest",
"description": "Aruba Virtual Mobility Controller",
"vendor_name": "HPE Aruba",
"vendor_url": "arubanetworks.com",
"vendor_url": "https://www.arubanetworks.com",
"product_name": "Aruba VMC",
"registry_version": 4,
"status": "stable",

View File

@ -24,6 +24,13 @@
"kvm": "require"
},
"images": [
{
"filename": "c8000v-universalk9_8G_serial.17.06.01a.qcow2",
"version": "17.06.01a 8G",
"md5sum": "d8b8ae633d953ec1b6d8f18a09a4f4e7",
"filesize": 1595277312,
"download_url": "https://software.cisco.com/download/home/286327102/type/282046477/release/Bengaluru-17.6.1a"
},
{
"filename": "c8000v-universalk9_8G_serial.17.04.01a.qcow2",
"version": "17.04.01a 8G",
@ -40,6 +47,12 @@
}
],
"versions": [
{
"name": "17.06.01a 8G",
"images": {
"hda_disk_image": "c8000v-universalk9_8G_serial.17.06.01a.qcow2"
}
},
{
"name": "17.04.01a 8G",
"images": {

View File

@ -18,6 +18,12 @@
"startup_config": "iou_l3_base_startup-config.txt"
},
"images": [
{
"filename": "i86bi_LinuxL3-AdvEnterpriseK9-M2_157_3_May_2018.bin",
"version": "15.7(3)M2",
"md5sum": "d6874260c3daeeb96d10fc844ae0b93b",
"filesize": 184759244
},
{
"filename": "i86bi-linux-l3-adventerprisek9-ms.155-2.T.bin",
"version": "155-2T",
@ -32,6 +38,12 @@
}
],
"versions": [
{
"name": "15.7(3)M2",
"images": {
"image": "i86bi_LinuxL3-AdvEnterpriseK9-M2_157_3_May_2018.bin"
}
},
{
"name": "155-2T",
"images": {

View File

@ -24,12 +24,12 @@
},
"images": [
{
"filename": "debian-11-genericcloud-amd64-20220328-962.qcow2",
"version": "11.3",
"md5sum": "7cf51e23747898485971a656ac2eb96d",
"filesize": 253296640,
"filename": "debian-11-genericcloud-amd64-20220711-1073.qcow2",
"version": "11.4",
"md5sum": "e8fadf4bbf7324a2e2875a5ba00588e7",
"filesize": 253231104,
"download_url": "https://cloud.debian.org/images/cloud/bullseye/",
"direct_download_url": "https://cloud.debian.org/images/cloud/bullseye/20220328-962/debian-11-genericcloud-amd64-20220328-962.qcow2"
"direct_download_url": "https://cloud.debian.org/images/cloud/bullseye/20220711-1073/debian-11-genericcloud-amd64-20220711-1073.qcow2"
},
{
"filename": "debian-10-genericcloud-amd64-20220328-962.qcow2",
@ -49,9 +49,9 @@
],
"versions": [
{
"name": "11.3",
"name": "11.4",
"images": {
"hda_disk_image": "debian-11-genericcloud-amd64-20220328-962.qcow2",
"hda_disk_image": "debian-11-genericcloud-amd64-20220711-1073.qcow2",
"cdrom_image": "debian-cloud-init-data.iso"
}
},

View File

@ -27,7 +27,14 @@
"options": "-cpu core2duo"
},
"images": [
{
{
"filename": "EXOS-VM_v32.1.1.6.qcow2",
"version": "32.1.1.6",
"md5sum": "48868bbcb4255d6365049b5941dd2af7",
"filesize": 231211008,
"direct_download_url": "https://akamai-ep.extremenetworks.com/Extreme_P/github-en/Virtual_EXOS/EXOS-VM_v32.1.1.6.qcow2"
},
{
"filename": "EXOS-VM_v31.7.1.4.qcow2",
"version": "31.7.1.4",
"md5sum": "a70e4fa3bc361434237ad12937aaf0fb",
@ -106,6 +113,12 @@
}
],
"versions": [
{
"name": "32.1.1.6",
"images": {
"hda_disk_image": "EXOS-VM_v32.1.1.6.qcow2"
}
},
{
"name": "31.7.1.4",
"images": {

View File

@ -11,7 +11,7 @@
"status": "experimental",
"availability": "service-contract",
"maintainer": "none",
"maintainer_email": "none",
"maintainer_email": "",
"usage": "Default user is super, default password is super.",
"port_name_format": "GigabitEthernet0/0/{0}",
"qemu": {

View File

@ -10,7 +10,7 @@
"status": "experimental",
"availability": "service-contract",
"maintainer": "none",
"maintainer_email": "none",
"maintainer_email": "",
"port_name_format": "GE1/0/{0}",
"qemu": {
"adapter_type": "e1000",

View File

@ -11,7 +11,7 @@
"status": "experimental",
"availability": "service-contract",
"maintainer": "none",
"maintainer_email": "none",
"maintainer_email": "",
"first_port_name": "eth0",
"port_name_format": "Ethernet1/0/{0}",
"qemu": {

View File

@ -11,7 +11,7 @@
"status": "experimental",
"availability": "service-contract",
"maintainer": "none",
"maintainer_email": "none",
"maintainer_email": "",
"usage": "Default password is admin. Default username and password for web is admin/Admin@123.",
"first_port_name": "GigabitEthernet0/0/0",
"port_name_format": "GigabitEthernet1/0/{0}",

View File

@ -12,13 +12,13 @@
"status": "experimental",
"maintainer": "none",
"maintainer_email": "developers@gns3.net",
"usage": "Initial username is root, password is root.\n",
"usage": "Connect VCP by port Eth1.\nData port ge/xe-x/0/0 to ge/xe-x/0/9 mapping to Eth3 to Eth12.\nInitial username is root, password is root.\n",
"symbol": "juniper-vmx.svg",
"first_port_name": "Eth0",
"port_name_format": "Eth{port1}",
"qemu": {
"adapter_type": "virtio-net-pci",
"adapters": 12,
"adapters": 13,
"ram": 4096,
"hda_disk_interface": "ide",
"arch": "x86_64",

View File

@ -28,6 +28,18 @@
"options": "-nographic -enable-kvm"
},
"images": [
{
"filename": "junos-x86-64-20.4R3.8.img",
"version": "20.4R3.8-KVM",
"md5sum": "69638ba0ad83d7a99a28b658b1dd8def",
"filesize": 2773090304
},
{
"filename": "metadata.img",
"version": "20.4R3.8-KVM",
"md5sum": "ae4e3562aa389929476d82420c79d511",
"filesize": 393216
},
{
"filename": "junos-x86-64-20.3R1.8.img",
"version": "20.3R1.8-KVM",
@ -42,6 +54,13 @@
}
],
"versions": [
{
"name": "20.4R3.8-KVM",
"images": {
"hda_disk_image": "junos-x86-64-20.4R3.8.img",
"hdb_disk_image": "metadata.img"
}
},
{
"name": "20.3R1.8-KVM",
"images": {

View File

@ -28,81 +28,81 @@
},
"images": [
{
"filename": "chr-7.1rc7.img",
"version": "7.1rc7",
"md5sum": "04bc0ae1e5fbbda1522135bc57cf6560",
"filename": "chr-7.4rc2.img",
"version": "7.4rc2",
"md5sum": "ddb107c95cc7d231f8d8bbdb4eebdab6",
"filesize": 134217728,
"download_url": "http://www.mikrotik.com/download",
"direct_download_url": "https://download.mikrotik.com/routeros/7.1rc7/chr-7.1rc7.img.zip",
"direct_download_url": "https://download.mikrotik.com/routeros/7.4rc2/chr-7.4rc2.img.zip",
"compression": "zip"
},
{
"filename": "chr-7.1.img",
"version": "7.1",
"md5sum": "41545bc7b55717fe5bb1e489ee39ca45",
"filename": "chr-7.3.1.img",
"version": "7.3.1",
"md5sum": "99f8ea75f8b745a8bf5ca3cc1bd325e3",
"filesize": 134217728,
"download_url": "http://www.mikrotik.com/download",
"direct_download_url": "https://download.mikrotik.com/routeros/7.1/chr-7.1.img.zip",
"direct_download_url": "https://download.mikrotik.com/routeros/7.3.1/chr-7.3.1.img.zip",
"compression": "zip"
},
{
"filename": "chr-6.49rc2.img",
"version": "6.49rc2",
"md5sum": "e1088f8f64ac3d6ecf2e56ac96261226",
"filesize": 67108864,
"filename": "chr-7.1.5.img",
"version": "7.1.5",
"md5sum": "9c0be05f891df2b1400bdae5e719898e",
"filesize": 134217728,
"download_url": "http://www.mikrotik.com/download",
"direct_download_url": "https://download.mikrotik.com/routeros/6.49rc2/chr-6.49rc2.img.zip",
"direct_download_url": "https://download.mikrotik.com/routeros/7.1.5/chr-7.1.5.img.zip",
"compression": "zip"
},
{
"filename": "chr-6.49.1.img",
"version": "6.49.1",
"md5sum": "6c896c4c853de99f2ea77f0f4b102261",
"filename": "chr-6.49.6.img",
"version": "6.49.6",
"md5sum": "ae27d38acc9c4dcd875e0f97bcae8d97",
"filesize": 67108864,
"download_url": "http://www.mikrotik.com/download",
"direct_download_url": "https://download.mikrotik.com/routeros/6.49.1/chr-6.49.1.img.zip",
"direct_download_url": "https://download.mikrotik.com/routeros/6.49.6/chr-6.49.6.img.zip",
"compression": "zip"
},
{
"filename": "chr-6.48.5.img",
"version": "6.48.5",
"md5sum": "d14debd4cd989f16f695b5b075960703",
"filename": "chr-6.48.6.img",
"version": "6.48.6",
"md5sum": "875574a561570227ff8f395aabe478c6",
"filesize": 67108864,
"download_url": "http://www.mikrotik.com/download",
"direct_download_url": "https://download.mikrotik.com/routeros/6.48.5/chr-6.48.5.img.zip",
"direct_download_url": "https://download.mikrotik.com/routeros/6.48.6/chr-6.48.6.img.zip",
"compression": "zip"
}
],
"versions": [
{
"name": "7.1rc7",
"name": "7.4rc2",
"images": {
"hda_disk_image": "chr-7.1rc7.img"
"hda_disk_image": "chr-7.4rc2.img"
}
},
{
"name": "7.1",
"name": "7.3.1",
"images": {
"hda_disk_image": "chr-7.1.img"
"hda_disk_image": "chr-7.3.1.img"
}
},
{
"name": "6.49rc2",
"name": "7.1.5",
"images": {
"hda_disk_image": "chr-6.49rc2.img"
"hda_disk_image": "chr-7.1.5.img"
}
},
{
"name": "6.49.1",
"name": "6.49.6",
"images": {
"hda_disk_image": "chr-6.49.1.img"
"hda_disk_image": "chr-6.49.6.img"
}
},
{
"name": "6.48.5",
"name": "6.48.6",
"images": {
"hda_disk_image": "chr-6.48.5.img"
"hda_disk_image": "chr-6.48.6.img"
}
}
]
}
}

View File

@ -29,8 +29,8 @@
"version": "0.4",
"md5sum": "e678698c97804901c7a53f6b68c8b861",
"filesize": 26476544,
"download_url": "https://www.b-ehlers.de/projects/netem/index.html",
"direct_download_url": "https://www.b-ehlers.de/projects/netem/NETem-v4.qcow2"
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/NETem-v4.qcow2/download"
}
],
"versions": [

View File

@ -11,7 +11,7 @@
"registry_version": 3,
"status": "stable",
"maintainer": "Mohamad Siblini",
"maintainer_email": "https://www.ictkin.com/contact",
"maintainer_email": "info@ictkin.com",
"usage": "Username: gns3\nPassword: gns3 | MD5: 435f15a54f7f673e302ad26f05226e0e",
"port_name_format": "ens{0}",
"qemu": {

View File

@ -33,6 +33,7 @@ from gns3server.utils.asyncio.raw_command_server import AsyncioRawCommandServer
from gns3server.utils.asyncio import wait_for_file_creation
from gns3server.utils.asyncio import monitor_process
from gns3server.utils.get_resource import get_resource
from gns3server.utils.hostname import is_rfc1123_hostname_valid
from gns3server.compute.ubridge.ubridge_error import UbridgeError, UbridgeNamespaceError
from ..base_node import BaseNode
@ -89,6 +90,9 @@ class DockerVM(BaseNode):
cpus=0,
):
if not is_rfc1123_hostname_valid(name):
raise DockerError(f"'{name}' is an invalid name to create a Docker node")
super().__init__(
name, node_id, project, manager, console=console, console_type=console_type, aux=aux, aux_type=aux_type
)
@ -171,6 +175,18 @@ class DockerVM(BaseNode):
return display
display += 1
@BaseNode.name.setter
def name(self, new_name):
"""
Sets the name of this Qemu VM.
:param new_name: name
"""
if not is_rfc1123_hostname_valid(new_name):
raise DockerError(f"'{new_name}' is an invalid name to rename Docker container '{self._name}'")
super(DockerVM, DockerVM).name.__set__(self, new_name)
@property
def ethernet_adapters(self):
return self._ethernet_adapters

View File

@ -37,6 +37,7 @@ from ..dynamips_error import DynamipsError
from gns3server.utils.file_watcher import FileWatcher
from gns3server.utils.asyncio import wait_run_in_executor, monitor_process
from gns3server.utils.hostname import is_ios_hostname_valid
from gns3server.utils.images import md5sum
@ -75,6 +76,9 @@ class Router(BaseNode):
ghost_flag=False,
):
if not is_ios_hostname_valid(name):
raise DynamipsError(f"{name} is an invalid name to create a Dynamips node")
super().__init__(
name, node_id, project, manager, console=console, console_type=console_type, aux=aux, aux_type=aux_type
)
@ -1653,6 +1657,9 @@ class Router(BaseNode):
:param new_name: new name string
"""
if not is_ios_hostname_valid(new_name):
raise DynamipsError(f"{new_name} is an invalid name to rename router '{self._name}'")
await self._hypervisor.send(f'vm rename "{self._name}" "{new_name}"')
# change the hostname in the startup-config

View File

@ -42,6 +42,7 @@ from .utils.iou_export import nvram_export
from gns3server.compute.ubridge.ubridge_error import UbridgeError
from gns3server.utils.file_watcher import FileWatcher
from gns3server.utils.asyncio.telnet_server import AsyncioTelnetServer
from gns3server.utils.hostname import is_ios_hostname_valid
from gns3server.utils.asyncio import locking
import gns3server.utils.asyncio
import gns3server.utils.images
@ -70,6 +71,9 @@ class IOUVM(BaseNode):
self, name, node_id, project, manager, application_id=None, path=None, console=None, console_type="telnet"
):
if not is_ios_hostname_valid(name):
raise IOUError(f"'{name}' is an invalid name to create an IOU node")
super().__init__(name, node_id, project, manager, console=console, console_type=console_type)
log.info(
@ -362,6 +366,8 @@ class IOUVM(BaseNode):
:param new_name: name
"""
if not is_ios_hostname_valid(new_name):
raise IOUError(f"'{new_name}' is an invalid name to rename IOU node '{self._name}'")
if self.startup_config_file:
content = self.startup_config_content
content = re.sub(r"hostname .+$", "hostname " + new_name, content, flags=re.MULTILINE)

View File

@ -22,7 +22,6 @@ order to run a QEMU VM.
import sys
import os
import re
import shlex
import math
import shutil
import struct
@ -47,6 +46,7 @@ from ..base_node import BaseNode
from ...utils.asyncio import monitor_process
from ...utils.images import md5sum
from ...utils import macaddress_to_int, int_to_macaddress
from ...utils.hostname import is_rfc1123_hostname_valid
from gns3server.schemas.compute.qemu_nodes import Qemu, QemuPlatform
@ -86,6 +86,9 @@ class QemuVM(BaseNode):
platform=None,
):
if not is_rfc1123_hostname_valid(name):
raise QemuError(f"'{name}' is an invalid name to create a Qemu node")
super().__init__(
name,
node_id,
@ -172,6 +175,18 @@ class QemuVM(BaseNode):
log.info(f'QEMU VM "{self._name}" [{self._id}] has been created')
@BaseNode.name.setter
def name(self, new_name):
"""
Sets the name of this Qemu VM.
:param new_name: name
"""
if not is_rfc1123_hostname_valid(new_name):
raise QemuError(f"'{new_name}' is an invalid name to rename Qemu node '{self._name}'")
super(QemuVM, QemuVM).name.__set__(self, new_name)
@property
def guest_cid(self):
"""

View File

@ -23,7 +23,7 @@ import socket
import json
import sys
import io
from operator import itemgetter
from fastapi import HTTPException
from aiohttp import web
from ..utils import parse_version
@ -576,12 +576,13 @@ class Compute:
# If the 409 doesn't come from a GNS3 server
except ValueError:
raise ControllerError(msg)
elif response.status == 500:
raise aiohttp.web.HTTPInternalServerError(text=f"Internal server error {url}")
elif response.status == 503:
raise aiohttp.web.HTTPServiceUnavailable(text=f"Service unavailable {url} {body}")
else:
raise NotImplementedError(f"{response.status} status code is not supported for {method} '{url}'\n{body}")
raise HTTPException(
status_code=response.status,
detail=f"HTTP error {response.status} received from compute "
f"'{self.name}' for request {method} {path}: {msg}"
)
if body and len(body):
if raw:
response.body = body

View File

@ -427,6 +427,7 @@ class Node:
# When updating properties used only on controller we don't need to call the compute
update_compute = False
old_json = self.asdict()
old_name = self._name
compute_properties = None
# Update node properties with additional elements
@ -454,7 +455,13 @@ class Node:
self._list_ports()
if update_compute:
data = self._node_data(properties=compute_properties)
response = await self.put(None, data=data)
try:
response = await self.put(None, data=data)
except ComputeConflictError:
if old_name != self.name:
# special case when the new name is already updated on controller but refused by the compute
self.name = old_name
raise
await self.parse_node_response(response.json)
elif old_json != self.asdict():
# We send notif only if object has changed

View File

@ -90,7 +90,7 @@ async def get_computes(app: FastAPI) -> List[dict]:
def image_filter(change: Change, path: str) -> bool:
if change == Change.added:
if change == Change.added and os.path.isfile(path):
if path.endswith(".tmp") or path.endswith(".md5sum") or path.startswith(".") or \
"/lib/" in path or "/lib64/" in path:
return False

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python
#
# Copyright (C) 2022 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
def is_ios_hostname_valid(hostname: str) -> bool:
"""
Check if an IOS hostname is valid
IOS hostname must start with a letter, end with a letter or digit, and
have as interior characters only letters, digits, and hyphens.
They must be 63 characters or fewer (ARPANET rules).
"""
if re.search(r"""^(?!-|[0-9])[a-zA-Z0-9-]{1,63}(?<!-)$""", hostname):
return True
return False
def is_rfc1123_hostname_valid(hostname: str) -> bool:
"""
Check if a hostname is valid according to RFC 1123
Each element of the hostname must be from 1 to 63 characters long
and the entire hostname, including the dots, can be at most 253
characters long. Valid characters for hostnames are ASCII
letters from a to z, the digits from 0 to 9, and the hyphen (-).
A hostname may not start with a hyphen.
"""
if hostname[-1] == ".":
hostname = hostname[:-1] # strip exactly one dot from the right, if present
if len(hostname) > 253:
return False
labels = hostname.split(".")
# the TLD must be not all-numeric
if re.match(r"[0-9]+$", labels[-1]):
return False
allowed = re.compile(r"(?!-)[a-zA-Z0-9-]{1,63}(?<!-)$")
return all(allowed.match(label) for label in labels)

View File

@ -33,7 +33,7 @@ def base_params() -> dict:
"""Return standard parameters"""
params = {
"name": "PC TEST 1",
"name": "DOCKER-TEST-1",
"image": "nginx",
"start_command": "nginx-daemon",
"adapters": 2,
@ -71,10 +71,11 @@ async def test_docker_create(app: FastAPI, compute_client: AsyncClient, compute_
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "nginx"}]):
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value={"Id": "8bd8153ea8f5"}):
response = await compute_client.post(app.url_path_for("compute:create_docker_node", project_id=compute_project.id),
json=base_params)
response = await compute_client.post(
app.url_path_for("compute:create_docker_node", project_id=compute_project.id), json=base_params
)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["name"] == "PC TEST 1"
assert response.json()["name"] == "DOCKER-TEST-1"
assert response.json()["project_id"] == compute_project.id
assert response.json()["container_id"] == "8bd8153ea8f5"
assert response.json()["image"] == "nginx:latest"
@ -84,6 +85,40 @@ async def test_docker_create(app: FastAPI, compute_client: AsyncClient, compute_
assert response.json()["extra_hosts"] == "test:127.0.0.1"
@pytest.mark.parametrize(
"name, status_code",
(
("valid-name.com", status.HTTP_201_CREATED),
("42name", status.HTTP_201_CREATED),
("424242", status.HTTP_409_CONFLICT),
("name42", status.HTTP_201_CREATED),
("name.424242", status.HTTP_409_CONFLICT),
("-name", status.HTTP_409_CONFLICT),
("name%-test", status.HTTP_409_CONFLICT),
("x" * 63, status.HTTP_201_CREATED),
("x" * 64, status.HTTP_409_CONFLICT),
(("x" * 62 + ".") * 4, status.HTTP_201_CREATED),
("xx" + ("x" * 62 + ".") * 4, status.HTTP_409_CONFLICT),
),
)
async def test_docker_create_with_invalid_name(
app: FastAPI,
compute_client: AsyncClient,
compute_project: Project,
base_params: dict,
name: str,
status_code: int
) -> None:
base_params["name"] = name
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "nginx"}]):
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value={"Id": "8bd8153ea8f5"}):
response = await compute_client.post(
app.url_path_for("compute:create_docker_node", project_id=compute_project.id), json=base_params
)
assert response.status_code == status_code
async def test_docker_start(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.start", return_value=True) as mock:

View File

@ -46,7 +46,7 @@ def fake_iou_bin(images_dir) -> str:
def base_params(tmpdir, fake_iou_bin) -> dict:
"""Return standard parameters"""
return {"application_id": 42, "name": "PC TEST 1", "path": "iou.bin"}
return {"application_id": 42, "name": "IOU-TEST-1", "path": "iou.bin"}
@pytest.fixture
@ -68,7 +68,7 @@ async def test_iou_create(app: FastAPI, compute_client: AsyncClient, compute_pro
response = await compute_client.post(app.url_path_for("compute:create_iou_node", project_id=compute_project.id), json=base_params)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["name"] == "PC TEST 1"
assert response.json()["name"] == "IOU-TEST-1"
assert response.json()["project_id"] == compute_project.id
assert response.json()["serial_adapters"] == 2
assert response.json()["ethernet_adapters"] == 2
@ -93,7 +93,7 @@ async def test_iou_create_with_params(app: FastAPI,
response = await compute_client.post(app.url_path_for("compute:create_iou_node", project_id=compute_project.id), json=params)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["name"] == "PC TEST 1"
assert response.json()["name"] == "IOU-TEST-1"
assert response.json()["project_id"] == compute_project.id
assert response.json()["serial_adapters"] == 4
assert response.json()["ethernet_adapters"] == 0
@ -106,6 +106,34 @@ async def test_iou_create_with_params(app: FastAPI,
assert f.read() == "hostname test"
@pytest.mark.parametrize(
"name, status_code",
(
("valid-name", status.HTTP_201_CREATED),
("42name", status.HTTP_409_CONFLICT),
("name42", status.HTTP_201_CREATED),
("-name", status.HTTP_409_CONFLICT),
("name%-test", status.HTTP_409_CONFLICT),
("x" * 63, status.HTTP_201_CREATED),
("x" * 64, status.HTTP_409_CONFLICT),
),
)
async def test_iou_create_with_invalid_name(
app: FastAPI,
compute_client: AsyncClient,
compute_project: Project,
base_params: dict,
name: str,
status_code: int
) -> None:
base_params["name"] = name
response = await compute_client.post(
app.url_path_for("compute:create_iou_node", project_id=compute_project.id), json=base_params
)
assert response.status_code == status_code
async def test_iou_create_startup_config_already_exist(
app: FastAPI,
compute_client: AsyncClient,
@ -133,7 +161,7 @@ async def test_iou_get(app: FastAPI, compute_client: AsyncClient, compute_projec
response = await compute_client.get(app.url_path_for("compute:get_iou_node", project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status_code == status.HTTP_200_OK
assert response.json()["name"] == "PC TEST 1"
assert response.json()["name"] == "IOU-TEST-1"
assert response.json()["project_id"] == compute_project.id
assert response.json()["serial_adapters"] == 2
assert response.json()["ethernet_adapters"] == 2

View File

@ -66,7 +66,7 @@ def fake_qemu_img_binary(tmpdir):
def base_params(tmpdir, fake_qemu_bin) -> dict:
"""Return standard parameters"""
return {"name": "PC TEST 1", "qemu_path": fake_qemu_bin}
return {"name": "QEMU-TEST-1", "qemu_path": fake_qemu_bin}
@pytest.fixture
@ -88,7 +88,7 @@ async def test_qemu_create(app: FastAPI,
response = await compute_client.post(app.url_path_for("compute:create_qemu_node", project_id=compute_project.id), json=base_params)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["name"] == "PC TEST 1"
assert response.json()["name"] == "QEMU-TEST-1"
assert response.json()["project_id"] == compute_project.id
assert response.json()["qemu_path"] == fake_qemu_bin
assert response.json()["platform"] == "x86_64"
@ -104,7 +104,7 @@ async def test_qemu_create_platform(app: FastAPI,
base_params["platform"] = "x86_64"
response = await compute_client.post(app.url_path_for("compute:create_qemu_node", project_id=compute_project.id), json=base_params)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["name"] == "PC TEST 1"
assert response.json()["name"] == "QEMU-TEST-1"
assert response.json()["project_id"] == compute_project.id
assert response.json()["qemu_path"] == fake_qemu_bin
assert response.json()["platform"] == "x86_64"
@ -122,13 +122,44 @@ async def test_qemu_create_with_params(app: FastAPI,
params["hda_disk_image"] = "linux载.img"
response = await compute_client.post(app.url_path_for("compute:create_qemu_node", project_id=compute_project.id), json=params)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["name"] == "PC TEST 1"
assert response.json()["name"] == "QEMU-TEST-1"
assert response.json()["project_id"] == compute_project.id
assert response.json()["ram"] == 1024
assert response.json()["hda_disk_image"] == "linux载.img"
assert response.json()["hda_disk_image_md5sum"] == "c4ca4238a0b923820dcc509a6f75849b"
@pytest.mark.parametrize(
"name, status_code",
(
("valid-name.com", status.HTTP_201_CREATED),
("42name", status.HTTP_201_CREATED),
("424242", status.HTTP_409_CONFLICT),
("name42", status.HTTP_201_CREATED),
("name.424242", status.HTTP_409_CONFLICT),
("-name", status.HTTP_409_CONFLICT),
("name%-test", status.HTTP_409_CONFLICT),
("x" * 63, status.HTTP_201_CREATED),
("x" * 64, status.HTTP_409_CONFLICT),
(("x" * 62 + ".") * 4, status.HTTP_201_CREATED),
("xx" + ("x" * 62 + ".") * 4, status.HTTP_409_CONFLICT),
),
)
async def test_qemu_create_with_invalid_name(
app: FastAPI,
compute_client: AsyncClient,
compute_project: Project,
base_params: dict,
name: str,
status_code: int
) -> None:
base_params["name"] = name
response = await compute_client.post(
app.url_path_for("compute:create_qemu_node", project_id=compute_project.id), json=base_params
)
assert response.status_code == status_code
# async def test_qemu_create_with_project_file(app: FastAPI,
# compute_client: AsyncClient,
# compute_project: Project,
@ -157,7 +188,7 @@ async def test_qemu_get(app: FastAPI, compute_client: AsyncClient, compute_proje
app.url_path_for("compute:get_qemu_node", project_id=qemu_vm["project_id"], node_id=qemu_vm["node_id"])
)
assert response.status_code == status.HTTP_200_OK
assert response.json()["name"] == "PC TEST 1"
assert response.json()["name"] == "QEMU-TEST-1"
assert response.json()["project_id"] == compute_project.id
assert response.json()["node_directory"] == os.path.join(
compute_project.path,