diff --git a/gns3server/api/routes/compute/__init__.py b/gns3server/api/routes/compute/__init__.py index 2453c0e8..041ada28 100644 --- a/gns3server/api/routes/compute/__init__.py +++ b/gns3server/api/routes/compute/__init__.py @@ -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, diff --git a/gns3server/api/routes/compute/atm_switch_nodes.py b/gns3server/api/routes/compute/atm_switch_nodes.py index 4dcab777..c50d745d 100644 --- a/gns3server/api/routes/compute/atm_switch_nodes.py +++ b/gns3server/api/routes/compute/atm_switch_nodes.py @@ -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") diff --git a/gns3server/api/routes/compute/cloud_nodes.py b/gns3server/api/routes/compute/cloud_nodes.py index 5ec5ea00..6dc135d5 100644 --- a/gns3server/api/routes/compute/cloud_nodes.py +++ b/gns3server/api/routes/compute/cloud_nodes.py @@ -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") diff --git a/gns3server/api/routes/compute/docker_nodes.py b/gns3server/api/routes/compute/docker_nodes.py index 61426730..e9a1e29f 100644 --- a/gns3server/api/routes/compute/docker_nodes.py +++ b/gns3server/api/routes/compute/docker_nodes.py @@ -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) diff --git a/gns3server/api/routes/compute/dynamips_nodes.py b/gns3server/api/routes/compute/dynamips_nodes.py index 96f3d67a..ea74ad25 100644 --- a/gns3server/api/routes/compute/dynamips_nodes.py +++ b/gns3server/api/routes/compute/dynamips_nodes.py @@ -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) diff --git a/gns3server/api/routes/compute/ethernet_hub_nodes.py b/gns3server/api/routes/compute/ethernet_hub_nodes.py index fe7999ee..c3b3af6c 100644 --- a/gns3server/api/routes/compute/ethernet_hub_nodes.py +++ b/gns3server/api/routes/compute/ethernet_hub_nodes.py @@ -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") diff --git a/gns3server/api/routes/compute/ethernet_switch_nodes.py b/gns3server/api/routes/compute/ethernet_switch_nodes.py index d3ca028b..8b30c476 100644 --- a/gns3server/api/routes/compute/ethernet_switch_nodes.py +++ b/gns3server/api/routes/compute/ethernet_switch_nodes.py @@ -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") diff --git a/gns3server/api/routes/compute/frame_relay_switch_nodes.py b/gns3server/api/routes/compute/frame_relay_switch_nodes.py index 9d0f61ce..32482621 100644 --- a/gns3server/api/routes/compute/frame_relay_switch_nodes.py +++ b/gns3server/api/routes/compute/frame_relay_switch_nodes.py @@ -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") diff --git a/gns3server/api/routes/compute/images.py b/gns3server/api/routes/compute/images.py index 1d185949..f32c07fd 100644 --- a/gns3server/api/routes/compute/images.py +++ b/gns3server/api/routes/compute/images.py @@ -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}") diff --git a/gns3server/api/routes/compute/iou_nodes.py b/gns3server/api/routes/compute/iou_nodes.py index 35d4f067..5b74acc9 100644 --- a/gns3server/api/routes/compute/iou_nodes.py +++ b/gns3server/api/routes/compute/iou_nodes.py @@ -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) diff --git a/gns3server/api/routes/compute/nat_nodes.py b/gns3server/api/routes/compute/nat_nodes.py index 8a0e930c..d271d279 100644 --- a/gns3server/api/routes/compute/nat_nodes.py +++ b/gns3server/api/routes/compute/nat_nodes.py @@ -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") diff --git a/gns3server/api/routes/compute/projects.py b/gns3server/api/routes/compute/projects.py index c35cbbe4..eca97c20 100644 --- a/gns3server/api/routes/compute/projects.py +++ b/gns3server/api/routes/compute/projects.py @@ -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) \ No newline at end of file diff --git a/gns3server/api/routes/compute/qemu_nodes.py b/gns3server/api/routes/compute/qemu_nodes.py index c5df55f7..b1b95417 100644 --- a/gns3server/api/routes/compute/qemu_nodes.py +++ b/gns3server/api/routes/compute/qemu_nodes.py @@ -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) diff --git a/gns3server/api/routes/compute/virtualbox_nodes.py b/gns3server/api/routes/compute/virtualbox_nodes.py index 351ad58f..18c28751 100644 --- a/gns3server/api/routes/compute/virtualbox_nodes.py +++ b/gns3server/api/routes/compute/virtualbox_nodes.py @@ -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) + diff --git a/gns3server/api/routes/compute/vmware_nodes.py b/gns3server/api/routes/compute/vmware_nodes.py index 59c25927..a289455b 100644 --- a/gns3server/api/routes/compute/vmware_nodes.py +++ b/gns3server/api/routes/compute/vmware_nodes.py @@ -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) + diff --git a/gns3server/api/routes/compute/vpcs_nodes.py b/gns3server/api/routes/compute/vpcs_nodes.py index e505e78f..df4f82c3 100644 --- a/gns3server/api/routes/compute/vpcs_nodes.py +++ b/gns3server/api/routes/compute/vpcs_nodes.py @@ -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") diff --git a/gns3server/api/routes/controller/appliances.py b/gns3server/api/routes/controller/appliances.py index 550473e1..05fba4ad 100644 --- a/gns3server/api/routes/controller/appliances.py +++ b/gns3server/api/routes/controller/appliances.py @@ -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) diff --git a/gns3server/api/routes/controller/computes.py b/gns3server/api/routes/controller/computes.py index 963ff099..ce8c1629 100644 --- a/gns3server/api/routes/controller/computes.py +++ b/gns3server/api/routes/controller/computes.py @@ -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]) diff --git a/gns3server/api/routes/controller/controller.py b/gns3server/api/routes/controller/controller.py index 51c9f0d4..a20de078 100644 --- a/gns3server/api/routes/controller/controller.py +++ b/gns3server/api/routes/controller/controller.py @@ -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( diff --git a/gns3server/api/routes/controller/dependencies/authentication.py b/gns3server/api/routes/controller/dependencies/authentication.py index c1e05b71..ce07e9b3 100644 --- a/gns3server/api/routes/controller/dependencies/authentication.py +++ b/gns3server/api/routes/controller/dependencies/authentication.py @@ -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: diff --git a/gns3server/api/routes/controller/drawings.py b/gns3server/api/routes/controller/drawings.py index accec9cf..18b0f80a 100644 --- a/gns3server/api/routes/controller/drawings.py +++ b/gns3server/api/routes/controller/drawings.py @@ -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) diff --git a/gns3server/api/routes/controller/groups.py b/gns3server/api/routes/controller/groups.py index c29a6fc1..85ebfdc0 100644 --- a/gns3server/api/routes/controller/groups.py +++ b/gns3server/api/routes/controller/groups.py @@ -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) diff --git a/gns3server/api/routes/controller/images.py b/gns3server/api/routes/controller/images.py index c23b04b9..031a9be2 100644 --- a/gns3server/api/routes/controller/images.py +++ b/gns3server/api/routes/controller/images.py @@ -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) diff --git a/gns3server/api/routes/controller/links.py b/gns3server/api/routes/controller/links.py index a1b092ba..c228751f 100644 --- a/gns3server/api/routes/controller/links.py +++ b/gns3server/api/routes/controller/links.py @@ -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") diff --git a/gns3server/api/routes/controller/nodes.py b/gns3server/api/routes/controller/nodes.py index b97eb70d..cdd94693 100644 --- a/gns3server/api/routes/controller/nodes.py +++ b/gns3server/api/routes/controller/nodes.py @@ -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) diff --git a/gns3server/api/routes/controller/permissions.py b/gns3server/api/routes/controller/permissions.py index 504f2c59..d5b31e1b 100644 --- a/gns3server/api/routes/controller/permissions.py +++ b/gns3server/api/routes/controller/permissions.py @@ -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) diff --git a/gns3server/api/routes/controller/projects.py b/gns3server/api/routes/controller/projects.py index f2c2855f..60a7d8a5 100644 --- a/gns3server/api/routes/controller/projects.py +++ b/gns3server/api/routes/controller/projects.py @@ -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}", diff --git a/gns3server/api/routes/controller/roles.py b/gns3server/api/routes/controller/roles.py index f0ed7f1f..2c9ee0d6 100644 --- a/gns3server/api/routes/controller/roles.py +++ b/gns3server/api/routes/controller/roles.py @@ -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) \ No newline at end of file diff --git a/gns3server/api/routes/controller/snapshots.py b/gns3server/api/routes/controller/snapshots.py index b1faa8cf..c372a8e8 100644 --- a/gns3server/api/routes/controller/snapshots.py +++ b/gns3server/api/routes/controller/snapshots.py @@ -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) diff --git a/gns3server/api/routes/controller/symbols.py b/gns3server/api/routes/controller/symbols.py index 40161672..c992570b 100644 --- a/gns3server/api/routes/controller/symbols.py +++ b/gns3server/api/routes/controller/symbols.py @@ -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) diff --git a/gns3server/api/routes/controller/templates.py b/gns3server/api/routes/controller/templates.py index c5982212..3dfe2ceb 100644 --- a/gns3server/api/routes/controller/templates.py +++ b/gns3server/api/routes/controller/templates.py @@ -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) diff --git a/gns3server/api/routes/controller/users.py b/gns3server/api/routes/controller/users.py index 8d1953f0..577e1167 100644 --- a/gns3server/api/routes/controller/users.py +++ b/gns3server/api/routes/controller/users.py @@ -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) diff --git a/gns3server/appliances/aruba-arubaoscx.gns3a b/gns3server/appliances/aruba-arubaoscx.gns3a index 39109f05..db45527b 100644 --- a/gns3server/appliances/aruba-arubaoscx.gns3a +++ b/gns3server/appliances/aruba-arubaoscx.gns3a @@ -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": { diff --git a/gns3server/appliances/aruba-vgw.gns3a b/gns3server/appliances/aruba-vgw.gns3a index 6592a204..67c3910a 100644 --- a/gns3server/appliances/aruba-vgw.gns3a +++ b/gns3server/appliances/aruba-vgw.gns3a @@ -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/", diff --git a/gns3server/appliances/aruba-vmc.gns3a b/gns3server/appliances/aruba-vmc.gns3a index 52ba75d4..7be2cca4 100644 --- a/gns3server/appliances/aruba-vmc.gns3a +++ b/gns3server/appliances/aruba-vmc.gns3a @@ -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", diff --git a/gns3server/appliances/cisco-c8000v.gns3a b/gns3server/appliances/cisco-c8000v.gns3a index 6c1828da..14ab53c8 100644 --- a/gns3server/appliances/cisco-c8000v.gns3a +++ b/gns3server/appliances/cisco-c8000v.gns3a @@ -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": { diff --git a/gns3server/appliances/cisco-iou-l3.gns3a b/gns3server/appliances/cisco-iou-l3.gns3a index 19a5380b..3b0ac2f0 100644 --- a/gns3server/appliances/cisco-iou-l3.gns3a +++ b/gns3server/appliances/cisco-iou-l3.gns3a @@ -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": { diff --git a/gns3server/appliances/debian.gns3a b/gns3server/appliances/debian.gns3a index 13f55861..4b98cc20 100644 --- a/gns3server/appliances/debian.gns3a +++ b/gns3server/appliances/debian.gns3a @@ -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" } }, diff --git a/gns3server/appliances/exos.gns3a b/gns3server/appliances/exos.gns3a index 6d596124..4b67b8ac 100644 --- a/gns3server/appliances/exos.gns3a +++ b/gns3server/appliances/exos.gns3a @@ -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": { diff --git a/gns3server/appliances/huawei-ar1kv.gns3a b/gns3server/appliances/huawei-ar1kv.gns3a index fdb1c9d1..f98698a7 100644 --- a/gns3server/appliances/huawei-ar1kv.gns3a +++ b/gns3server/appliances/huawei-ar1kv.gns3a @@ -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": { diff --git a/gns3server/appliances/huawei-ce12800.gns3a b/gns3server/appliances/huawei-ce12800.gns3a index cf5cf6fb..8626d8cb 100644 --- a/gns3server/appliances/huawei-ce12800.gns3a +++ b/gns3server/appliances/huawei-ce12800.gns3a @@ -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", diff --git a/gns3server/appliances/huawei-ne40e.gns3a b/gns3server/appliances/huawei-ne40e.gns3a index 8a039a7c..4248f204 100644 --- a/gns3server/appliances/huawei-ne40e.gns3a +++ b/gns3server/appliances/huawei-ne40e.gns3a @@ -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": { diff --git a/gns3server/appliances/huawei-usg6kv.gns3a b/gns3server/appliances/huawei-usg6kv.gns3a index f2d0506c..010a4039 100644 --- a/gns3server/appliances/huawei-usg6kv.gns3a +++ b/gns3server/appliances/huawei-usg6kv.gns3a @@ -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}", diff --git a/gns3server/appliances/juniper-vmx-vfp.gns3a b/gns3server/appliances/juniper-vmx-vfp.gns3a index 626a3c3c..11708d3c 100644 --- a/gns3server/appliances/juniper-vmx-vfp.gns3a +++ b/gns3server/appliances/juniper-vmx-vfp.gns3a @@ -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", diff --git a/gns3server/appliances/juniper-vrr.gns3a b/gns3server/appliances/juniper-vrr.gns3a index f1892c30..acfe6a9c 100644 --- a/gns3server/appliances/juniper-vrr.gns3a +++ b/gns3server/appliances/juniper-vrr.gns3a @@ -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": { diff --git a/gns3server/appliances/mikrotik-chr.gns3a b/gns3server/appliances/mikrotik-chr.gns3a index 4175e369..69092601 100644 --- a/gns3server/appliances/mikrotik-chr.gns3a +++ b/gns3server/appliances/mikrotik-chr.gns3a @@ -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" } } ] -} +} \ No newline at end of file diff --git a/gns3server/appliances/netem.gns3a b/gns3server/appliances/netem.gns3a index 85302f39..ce071fa8 100644 --- a/gns3server/appliances/netem.gns3a +++ b/gns3server/appliances/netem.gns3a @@ -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": [ diff --git a/gns3server/appliances/ubuntu-server.gns3a b/gns3server/appliances/ubuntu-server.gns3a index 13cabbed..534be61c 100644 --- a/gns3server/appliances/ubuntu-server.gns3a +++ b/gns3server/appliances/ubuntu-server.gns3a @@ -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": { diff --git a/gns3server/compute/docker/docker_vm.py b/gns3server/compute/docker/docker_vm.py index d84d8ffa..01212982 100644 --- a/gns3server/compute/docker/docker_vm.py +++ b/gns3server/compute/docker/docker_vm.py @@ -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 diff --git a/gns3server/compute/dynamips/nodes/router.py b/gns3server/compute/dynamips/nodes/router.py index 046548a6..1487ff2a 100644 --- a/gns3server/compute/dynamips/nodes/router.py +++ b/gns3server/compute/dynamips/nodes/router.py @@ -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 diff --git a/gns3server/compute/iou/iou_vm.py b/gns3server/compute/iou/iou_vm.py index 9926dcc6..50e132c1 100644 --- a/gns3server/compute/iou/iou_vm.py +++ b/gns3server/compute/iou/iou_vm.py @@ -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) diff --git a/gns3server/compute/qemu/qemu_vm.py b/gns3server/compute/qemu/qemu_vm.py index 313a5c32..7fe17f70 100644 --- a/gns3server/compute/qemu/qemu_vm.py +++ b/gns3server/compute/qemu/qemu_vm.py @@ -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): """ diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index 29201759..9bc2372f 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -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 diff --git a/gns3server/controller/node.py b/gns3server/controller/node.py index 9d1673af..ddb1acba 100644 --- a/gns3server/controller/node.py +++ b/gns3server/controller/node.py @@ -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 diff --git a/gns3server/db/tasks.py b/gns3server/db/tasks.py index 4a106ffe..d879fbb3 100644 --- a/gns3server/db/tasks.py +++ b/gns3server/db/tasks.py @@ -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 diff --git a/gns3server/utils/hostname.py b/gns3server/utils/hostname.py new file mode 100644 index 00000000..2e89b685 --- /dev/null +++ b/gns3server/utils/hostname.py @@ -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 . + +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}(? 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}(? 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: diff --git a/tests/api/routes/compute/test_iou_nodes.py b/tests/api/routes/compute/test_iou_nodes.py index 49ba42f3..61309345 100644 --- a/tests/api/routes/compute/test_iou_nodes.py +++ b/tests/api/routes/compute/test_iou_nodes.py @@ -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 diff --git a/tests/api/routes/compute/test_qemu_nodes.py b/tests/api/routes/compute/test_qemu_nodes.py index c57bb2e0..9cc14bf8 100644 --- a/tests/api/routes/compute/test_qemu_nodes.py +++ b/tests/api/routes/compute/test_qemu_nodes.py @@ -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,