Use dependencies and group common HTTP responses in endpoints.

This commit is contained in:
grossmj committed 2020-10-14 10:49:29 +10:30
1 parent 58c5965905
commit 5341ccdbd6
28 files changed
+1376 -1386

No files matched your search

+4 -4
View File
@@ -33,12 +33,12 @@ router = APIRouter()
router.include_router(controller.router, tags=["controller"])
router.include_router(appliances.router, prefix="/appliances", tags=["appliances"])
router.include_router(computes.router, prefix="/computes", tags=["computes"])
router.include_router(drawings.router, tags=["drawings"])
router.include_router(drawings.router, prefix="/projects/{project_id}/drawings", tags=["drawings"])
router.include_router(gns3vm.router, prefix="/gns3vm", tags=["GNS3 VM"])
router.include_router(links.router, tags=["links"])
router.include_router(nodes.router, tags=["nodes"])
router.include_router(links.router, prefix="/projects/{project_id}/links", tags=["links"])
router.include_router(nodes.router, prefix="/projects/{project_id}/nodes", tags=["nodes"])
router.include_router(notifications.router, prefix="/notifications", tags=["notifications"])
router.include_router(projects.router, prefix="/projects", tags=["projects"])
router.include_router(snapshots.router, tags=["snapshots"])
router.include_router(snapshots.router, prefix="/projects/{project_id}/snapshots", tags=["snapshots"])
router.include_router(symbols.router, prefix="/symbols", tags=["symbols"])
router.include_router(templates.router, tags=["templates"])
@@ -25,8 +25,11 @@ from typing import Optional
router = APIRouter()
@router.get("/", summary="List of appliances")
async def list_appliances(update: Optional[bool] = None, symbol_theme: Optional[str] = "Classic"):
@router.get("/")
async def get_appliances(update: Optional[bool] = None, symbol_theme: Optional[str] = "Classic"):
"""
Return all appliances known by the controller.
"""
from gns3server.controller import Controller
controller = Controller.instance()
+26 -33
View File
@@ -30,9 +30,12 @@ from gns3server.endpoints import schemas
router = APIRouter()
responses = {
404: {"model": ErrorMessage, "description": "Compute not found"}
}
@router.post("/",
summary="Create a new compute",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Compute,
responses={404: {"model": ErrorMessage, "description": "Could not connect to compute"},
@@ -49,14 +52,12 @@ async def create_compute(compute_data: schemas.ComputeCreate):
@router.get("/{compute_id}",
summary="Get a compute",
response_model=schemas.Compute,
response_description="Compute data",
response_model_exclude_unset=True,
responses={404: {"model": ErrorMessage, "description": "Compute not found"}})
responses=responses)
def get_compute(compute_id: Union[str, UUID]):
"""
Get compute data from the controller.
Return a compute from the controller.
"""
compute = Controller.instance().get_compute(str(compute_id))
@@ -64,13 +65,11 @@ def get_compute(compute_id: Union[str, UUID]):
@router.get("/",
summary="List of all computes",
response_model=List[schemas.Compute],
response_description="List of computes",
response_model_exclude_unset=True)
async def list_computes():
async def get_computes():
"""
Return the list of all computes known by the controller.
Return all computes known by the controller.
"""
controller = Controller.instance()
@@ -78,11 +77,9 @@ async def list_computes():
@router.put("/{compute_id}",
summary="Update a compute",
response_model=schemas.Compute,
response_description="Updated compute",
response_model_exclude_unset=True,
responses={404: {"model": ErrorMessage, "description": "Compute not found"}})
responses=responses)
async def update_compute(compute_id: Union[str, UUID], compute_data: schemas.ComputeUpdate):
"""
Update a compute on the controller.
@@ -95,9 +92,8 @@ async def update_compute(compute_id: Union[str, UUID], compute_data: schemas.Com
@router.delete("/{compute_id}",
summary="Delete a compute",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Compute was not found"}})
responses=responses)
async def delete_compute(compute_id: Union[str, UUID]):
"""
Delete a compute from the controller.
@@ -107,10 +103,8 @@ async def delete_compute(compute_id: Union[str, UUID]):
@router.get("/{compute_id}/{emulator}/images",
summary="List images",
response_description="List of images",
responses={404: {"model": ErrorMessage, "description": "Compute was not found"}})
async def list_images(compute_id: Union[str, UUID], emulator: str):
responses=responses)
async def get_images(compute_id: Union[str, UUID], emulator: str):
"""
Return the list of images available on a compute for a given emulator type.
"""
@@ -121,23 +115,24 @@ async def list_images(compute_id: Union[str, UUID], emulator: str):
@router.get("/{compute_id}/{emulator}/{endpoint_path:path}",
summary="Forward GET request to a compute",
responses={404: {"model": ErrorMessage, "description": "Compute was not found"}})
responses=responses)
async def forward_get(compute_id: Union[str, UUID], emulator: str, endpoint_path: str):
"""
Forward GET request to a compute. Read the full compute API documentation for available endpoints.
Forward a GET request to a compute.
Read the full compute API documentation for available endpoints.
"""
compute = Controller.instance().get_compute(str(compute_id))
result = await compute.forward("GET", emulator, endpoint_path)
return result
@router.post("/{compute_id}/{emulator}/{endpoint_path:path}",
summary="Forward POST request to a compute",
responses={404: {"model": ErrorMessage, "description": "Compute was not found"}})
responses=responses)
async def forward_post(compute_id: Union[str, UUID], emulator: str, endpoint_path: str, compute_data: dict):
"""
Forward POST request to a compute. Read the full compute API documentation for available endpoints.
Forward a POST request to a compute.
Read the full compute API documentation for available endpoints.
"""
compute = Controller.instance().get_compute(str(compute_id))
@@ -145,11 +140,11 @@ async def forward_post(compute_id: Union[str, UUID], emulator: str, endpoint_pat
@router.put("/{compute_id}/{emulator}/{endpoint_path:path}",
summary="Forward PUT request to a compute",
responses={404: {"model": ErrorMessage, "description": "Compute was not found"}})
responses=responses)
async def forward_put(compute_id: Union[str, UUID], emulator: str, endpoint_path: str, compute_data: dict):
"""
Forward PUT request to a compute. Read the full compute API documentation for available endpoints.
Forward a PUT request to a compute.
Read the full compute API documentation for available endpoints.
"""
compute = Controller.instance().get_compute(str(compute_id))
@@ -157,11 +152,10 @@ async def forward_put(compute_id: Union[str, UUID], emulator: str, endpoint_path
@router.post("/{compute_id}/auto_idlepc",
summary="Find a new IDLE-PC value",
responses={404: {"model": ErrorMessage, "description": "Compute was not found"}})
responses=responses)
async def autoidlepc(compute_id: Union[str, UUID], auto_idle_pc: schemas.AutoIdlePC):
"""
Find a suitable Idle-PC value for a given IOS image. This may take some time.
Find a suitable Idle-PC value for a given IOS image. This may take a few minutes.
"""
controller = Controller.instance()
@@ -172,12 +166,11 @@ async def autoidlepc(compute_id: Union[str, UUID], auto_idle_pc: schemas.AutoIdl
@router.get("/{compute_id}/ports",
summary="Get ports used by a compute",
deprecated=True,
responses={404: {"model": ErrorMessage, "description": "Compute was not found"}})
responses=responses)
async def ports(compute_id: Union[str, UUID]):
"""
Get ports information for a given compute.
Return ports information for a given compute.
"""
return await Controller.instance().compute_ports(str(compute_id))
@@ -37,7 +37,6 @@ router = APIRouter()
@router.post("/shutdown",
summary="Shutdown the local server",
status_code=status.HTTP_204_NO_CONTENT,
responses={403: {"model": ErrorMessage, "description": "Server shutdown not allowed"}})
async def shutdown():
@@ -75,7 +74,7 @@ async def shutdown():
response_model=schemas.Version)
def version():
"""
Retrieve the server version number.
Return the server version number.
"""
config = Config.instance()
@@ -106,7 +105,7 @@ def check_version(version: schemas.Version):
response_model=schemas.IOULicense)
def get_iou_license():
"""
Get the IOU license settings
Return the IOU license settings
"""
return Controller.instance().iou_license
@@ -130,7 +129,7 @@ async def update_iou_license(iou_license: schemas.IOULicense):
@router.get("/statistics")
async def statistics():
"""
Retrieve server statistics.
Return server statistics.
"""
compute_statistics = []
+20 -21
View File
@@ -30,13 +30,15 @@ from gns3server.endpoints.schemas.drawings import Drawing
router = APIRouter()
responses = {
404: {"model": ErrorMessage, "description": "Project or drawing not found"}
}
@router.get("/projects/{project_id}/drawings",
summary="List of all drawings",
@router.get("/",
response_model=List[Drawing],
response_description="List of drawings",
response_model_exclude_unset=True)
async def list_drawings(project_id: UUID):
async def get_drawings(project_id: UUID):
"""
Return the list of all drawings for a given project.
"""
@@ -45,27 +47,27 @@ async def list_drawings(project_id: UUID):
return [v.__json__() for v in project.drawings.values()]
@router.post("/projects/{project_id}/drawings",
summary="Create a new drawing",
@router.post("/",
status_code=status.HTTP_201_CREATED,
response_model=Drawing,
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
responses=responses)
async def create_drawing(project_id: UUID, drawing_data: Drawing):
"""
Create a new drawing.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
drawing = await project.add_drawing(**jsonable_encoder(drawing_data, exclude_unset=True))
return drawing.__json__()
@router.get("/projects/{project_id}/drawings/{drawing_id}",
summary="Get a drawing",
@router.get("/{drawing_id}",
response_model=Drawing,
response_description="Drawing data",
response_model_exclude_unset=True,
responses={404: {"model": ErrorMessage, "description": "Project or drawing not found"}})
responses=responses)
async def get_drawing(project_id: UUID, drawing_id: UUID):
"""
Get drawing data for a given project from the controller.
Return a drawing.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
@@ -73,15 +75,13 @@ async def get_drawing(project_id: UUID, drawing_id: UUID):
return drawing.__json__()
@router.put("/projects/{project_id}/drawings/{drawing_id}",
summary="Update a drawing",
@router.put("/{drawing_id}",
response_model=Drawing,
response_description="Updated drawing",
response_model_exclude_unset=True,
responses={404: {"model": ErrorMessage, "description": "Project or drawing not found"}})
responses=responses)
async def update_drawing(project_id: UUID, drawing_id: UUID, drawing_data: Drawing):
"""
Update a drawing for a given project on the controller.
Update a drawing.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
@@ -90,13 +90,12 @@ async def update_drawing(project_id: UUID, drawing_id: UUID, drawing_data: Drawi
return drawing.__json__()
@router.delete("/projects/{project_id}/drawings/{drawing_id}",
summary="Delete a drawing",
@router.delete("/{drawing_id}",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Project or drawing not found"}})
responses=responses)
async def delete_drawing(project_id: UUID, drawing_id: UUID):
"""
Update a drawing for a given project from the controller.
Delete a drawing.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
+10 -9
View File
@@ -28,9 +28,8 @@ from gns3server.endpoints.schemas.gns3vm import GNS3VM
router = APIRouter()
@router.get("/engines",
summary="List of engines")
async def list_engines():
@router.get("/engines")
async def get_engines():
"""
Return the list of supported engines for the GNS3VM.
"""
@@ -39,11 +38,10 @@ async def list_engines():
return gns3_vm.engine_list()
@router.get("/engines/{engine}/vms",
summary="List of VMs")
@router.get("/engines/{engine}/vms")
async def get_vms(engine: str):
"""
Get all the available VMs for a specific virtualization engine.
Return all the available VMs for a specific virtualization engine.
"""
vms = await Controller.instance().gns3vm.list(engine)
@@ -51,19 +49,22 @@ async def get_vms(engine: str):
@router.get("/",
summary="Get GNS3 VM settings",
response_model=GNS3VM)
async def get_gns3vm_settings():
"""
Return the GNS3 VM settings.
"""
return Controller.instance().gns3vm.__json__()
@router.put("/",
summary="Update GNS3 VM settings",
response_model=GNS3VM,
response_description="Updated GNS3 VM settings",
response_model_exclude_unset=True)
async def update_gns3vm_settings(gns3vm_data: GNS3VM):
"""
Update the GNS3 VM settings.
"""
controller = Controller().instance()
gns3_vm = controller.gns3vm
+66 -67
View File
@@ -19,7 +19,7 @@
API endpoints for links.
"""
from fastapi import APIRouter, Request, status
from fastapi import APIRouter, Depends, Request, status
from fastapi.encoders import jsonable_encoder
from fastapi.responses import StreamingResponse
from typing import List
@@ -27,36 +27,47 @@ from uuid import UUID
from gns3server.controller import Controller
from gns3server.controller.controller_error import ControllerError
from gns3server.controller.link import Link
from gns3server.endpoints.schemas.common import ErrorMessage
from gns3server.endpoints.schemas.links import Link
import aiohttp
import multidict
from gns3server.endpoints import schemas
router = APIRouter()
responses = {
404: {"model": ErrorMessage, "description": "Could not find project or link"}
}
@router.get("/projects/{project_id}/links",
summary="List of all links",
response_model=List[Link],
response_description="List of links",
async def dep_link(project_id: UUID, link_id: UUID):
"""
Dependency to retrieve a link.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
link = project.get_link(str(link_id))
return link
@router.get("/",
response_model=List[schemas.Link],
response_model_exclude_unset=True)
async def list_links(project_id: UUID):
async def get_links(project_id: UUID):
"""
Return all links for a given project.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
return [v.__json__() for v in project.links.values()]
@router.post("/projects/{project_id}/links",
summary="Create a new link",
@router.post("/",
status_code=status.HTTP_201_CREATED,
response_model=Link,
response_model=schemas.Link,
responses={404: {"model": ErrorMessage, "description": "Could not find project"},
409: {"model": ErrorMessage, "description": "Could not create link"}})
async def create_link(project_id: UUID, link_data: Link):
async def create_link(project_id: UUID, link_data: schemas.Link):
"""
Create a new link on the controller.
Create a new link.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
@@ -78,42 +89,37 @@ async def create_link(project_id: UUID, link_data: Link):
return link.__json__()
@router.get("/projects/{project_id}/links/{link_id}/available_filters",
summary="List of filters",
responses={404: {"model": ErrorMessage, "description": "Could not find project or link"}})
async def list_filters(project_id: UUID, link_id: UUID):
@router.get("/{link_id}/available_filters",
responses=responses)
async def get_filters(link: Link = Depends(dep_link)):
"""
Return the list of filters available for this link.
Return all filters available for a given link.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
link = project.get_link(str(link_id))
return link.available_filters()
@router.get("/projects/{project_id}/links/{link_id}",
summary="Get a link",
response_model=Link,
response_description="Link data",
@router.get("/{link_id}",
response_model=schemas.Link,
response_model_exclude_unset=True,
responses={404: {"model": ErrorMessage, "description": "Could not find project or link"}})
async def get_link(project_id: UUID, link_id: UUID):
responses=responses)
async def get_link(link: Link = Depends(dep_link)):
"""
Return a link.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
link = project.get_link(str(link_id))
return link.__json__()
@router.put("/projects/{project_id}/links/{link_id}",
summary="Update a link",
response_model=Link,
response_description="Updated link",
@router.put("/{link_id}",
response_model=schemas.Link,
response_model_exclude_unset=True,
responses={404: {"model": ErrorMessage, "description": "Project or link not found"}})
async def update_link(project_id: UUID, link_id: UUID, link_data: Link):
responses=responses)
async def update_link(link_data: schemas.Link, link: Link = Depends(dep_link)):
"""
Update a link.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
link = project.get_link(str(link_id))
link_data = jsonable_encoder(link_data, exclude_unset=True)
if "filters" in link_data:
await link.update_filters(link_data["filters"])
@@ -124,60 +130,53 @@ async def update_link(project_id: UUID, link_id: UUID, link_data: Link):
return link.__json__()
@router.post("/projects/{project_id}/links/{link_id}/start_capture",
summary="Start a packet capture",
@router.post("/{link_id}/start_capture",
status_code=status.HTTP_201_CREATED,
response_model=Link,
responses={404: {"model": ErrorMessage, "description": "Project or link not found"}})
async def start_capture(project_id: UUID, link_id: UUID, capture_data: dict):
response_model=schemas.Link,
responses=responses)
async def start_capture(capture_data: dict, link: Link = Depends(dep_link)):
"""
Start packet capture on the link.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
link = project.get_link(str(link_id))
await link.start_capture(data_link_type=capture_data.get("data_link_type", "DLT_EN10MB"),
capture_file_name=capture_data.get("capture_file_name"))
return link.__json__()
@router.post("/projects/{project_id}/links/{link_id}/stop_capture",
summary="Stop a packet capture",
@router.post("/{link_id}/stop_capture",
status_code=status.HTTP_201_CREATED,
response_model=Link,
responses={404: {"model": ErrorMessage, "description": "Project or link not found"}})
async def stop_capture(project_id: UUID, link_id: UUID):
response_model=schemas.Link,
responses=responses)
async def stop_capture(link: Link = Depends(dep_link)):
"""
Stop packet capture on the link.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
link = project.get_link(str(link_id))
await link.stop_capture()
return link.__json__()
@router.delete("/projects/{project_id}/links/{link_id}",
summary="Delete a link",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Project or link not found"}})
async def delete(project_id: UUID, link_id: UUID):
@router.delete("/{link_id}",
status_code=status.HTTP_204_NO_CONTENT,
responses=responses)
async def delete_link(project_id: UUID, link: Link = Depends(dep_link)):
"""
Delete link from the project.
Delete a link.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
await project.delete_link(str(link_id))
await project.delete_link(link.id)
@router.post("/projects/{project_id}/links/{link_id}/reset",
summary="Reset a link",
response_model=Link,
responses={404: {"model": ErrorMessage, "description": "Project or link not found"}})
async def reset(project_id: UUID, link_id: UUID):
@router.post("/{link_id}/reset",
response_model=schemas.Link,
responses=responses)
async def reset_link(link: Link = Depends(dep_link)):
"""
Reset a link.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
link = project.get_link(str(link_id))
await link.reset()
return link.__json__()
+144 -145
View File
@@ -21,28 +21,28 @@ API endpoints for nodes.
import asyncio
from fastapi import APIRouter, Request, Response, status
from fastapi import APIRouter, Depends, Request, Response, status
from fastapi.encoders import jsonable_encoder
from fastapi.routing import APIRoute
from typing import List, Callable
from uuid import UUID
from gns3server.controller import Controller
from gns3server.controller.node import Node
from gns3server.controller.project import Project
from gns3server.utils import force_unix_path
from gns3server.controller.controller_error import ControllerForbiddenError
from gns3server.endpoints.schemas.common import ErrorMessage
from gns3server.endpoints import schemas
import aiohttp
node_locks = {}
class NodeConcurrency(APIRoute):
"""
To avoid strange effect we prevent concurrency
To avoid strange effects, we prevent concurrency
between the same instance of the node
(excepting when streaming a PCAP file and WebSocket consoles).
(excepting when streaming a PCAP file and for WebSocket consoles).
"""
def get_route_handler(self) -> Callable:
@@ -74,25 +74,41 @@ class NodeConcurrency(APIRoute):
router = APIRouter(route_class=NodeConcurrency)
# # dependency to retrieve a node
# async def get_node(project_id: UUID, node_id: UUID):
#
# project = await Controller.instance().get_loaded_project(str(project_id))
# node = project.get_node(str(node_id))
# return node
responses = {
404: {"model": ErrorMessage, "description": "Could not find project or node"}
}
@router.post("/projects/{project_id}/nodes",
summary="Create a new node",
async def dep_project(project_id: UUID):
"""
Dependency to retrieve a project.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
return project
async def dep_node(node_id: UUID, project: Project = Depends(dep_project)):
"""
Dependency to retrieve a node.
"""
node = project.get_node(str(node_id))
return node
@router.post("/",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Node,
responses={404: {"model": ErrorMessage, "description": "Could not find project"},
409: {"model": ErrorMessage, "description": "Could not create node"}})
async def create_node(project_id: UUID, node_data: schemas.Node):
async def create_node(node_data: schemas.Node, project: Project = Depends(dep_project)):
"""
Create a new node.
"""
controller = Controller.instance()
compute = controller.get_compute(str(node_data.compute_id))
project = await controller.get_loaded_project(str(project_id))
node_data = jsonable_encoder(node_data, exclude_unset=True)
node = await project.add_node(compute,
node_data.pop("name"),
@@ -101,91 +117,82 @@ async def create_node(project_id: UUID, node_data: schemas.Node):
return node.__json__()
@router.get("/projects/{project_id}/nodes",
summary="List of all nodes",
@router.get("/",
response_model=List[schemas.Node],
response_description="List of nodes",
response_model_exclude_unset=True)
async def list_nodes(project_id: UUID):
async def get_nodes(project: Project = Depends(dep_project)):
"""
Return all nodes belonging to a given project.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
return [v.__json__() for v in project.nodes.values()]
@router.post("/projects/{project_id}/nodes/start",
summary="Start all nodes",
@router.post("/start",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
async def start_all_nodes(project_id: UUID):
responses=responses)
async def start_all_nodes(project: Project = Depends(dep_project)):
"""
Start all nodes belonging to the project
Start all nodes belonging to a given project.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
await project.start_all()
@router.post("/projects/{project_id}/nodes/stop",
summary="Stop all nodes",
@router.post("/stop",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
async def stop_all_nodes(project_id: UUID):
responses=responses)
async def stop_all_nodes(project: Project = Depends(dep_project)):
"""
Stop all nodes belonging to the project
Stop all nodes belonging to a given project.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
await project.stop_all()
@router.post("/projects/{project_id}/nodes/suspend",
summary="Stop all nodes",
@router.post("/suspend",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
async def suspend_all_nodes(project_id: UUID):
responses=responses)
async def suspend_all_nodes(project: Project = Depends(dep_project)):
"""
Suspend all nodes belonging to the project
Suspend all nodes belonging to a given project.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
await project.suspend_all()
@router.post("/projects/{project_id}/nodes/reload",
summary="Reload all nodes",
@router.post("/reload",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
async def reload_all_nodes(project_id: UUID):
responses=responses)
async def reload_all_nodes(project: Project = Depends(dep_project)):
"""
Reload all nodes belonging to the project
Reload all nodes belonging to a given project.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
await project.stop_all()
await project.start_all()
@router.get("/projects/{project_id}/nodes/{node_id}",
summary="Get a node",
@router.get("/{node_id}",
response_model=schemas.Node,
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
def get_node(project_id: UUID, node_id: UUID):
responses=responses)
def get_node(node: Node = Depends(dep_node)):
"""
Return a node from a given project.
"""
project = Controller.instance().get_project(str(project_id))
node = project.get_node(str(node_id))
return node.__json__()
@router.put("/projects/{project_id}/nodes/{node_id}",
summary="Update a node",
@router.put("/{node_id}",
response_model=schemas.Node,
response_description="Updated node",
response_model_exclude_unset=True,
responses={404: {"model": ErrorMessage, "description": "Project or node not found"}})
async def update_node(project_id: UUID, node_id: UUID, node_data: schemas.NodeUpdate):
responses=responses)
async def update_node(node_data: schemas.NodeUpdate, node: Node = Depends(dep_node)):
"""
Update a node.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
node_data = jsonable_encoder(node_data, exclude_unset=True)
# Ignore these because we only use them when creating a node
@@ -197,139 +204,129 @@ async def update_node(project_id: UUID, node_id: UUID, node_data: schemas.NodeUp
return node.__json__()
@router.delete("/projects/{project_id}/nodes/{node_id}",
summary="Delete a node",
@router.delete("/{node_id}",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"},
responses={**responses,
409: {"model": ErrorMessage, "description": "Cannot delete node"}})
async def delete_node(project_id: UUID, node_id: UUID):
async def delete_node(node_id: UUID, project: Project = Depends(dep_project)):
"""
Delete a node from a project.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
await project.delete_node(str(node_id))
@router.post("/projects/{project_id}/nodes/{node_id}/duplicate",
summary="Duplicate a node",
@router.post("/{node_id}/duplicate",
response_model=schemas.Node,
status_code=status.HTTP_201_CREATED,
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
async def duplicate_node(project_id: UUID, node_id: UUID, duplicate_data: schemas.NodeDuplicate):
responses=responses)
async def duplicate_node(duplicate_data: schemas.NodeDuplicate, node: Node = Depends(dep_node)):
"""
Duplicate a node.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
new_node = await project.duplicate_node(node,
duplicate_data.x,
duplicate_data.y,
duplicate_data.z)
new_node = await node.project.duplicate_node(node,
duplicate_data.x,
duplicate_data.y,
duplicate_data.z)
return new_node.__json__()
@router.post("/projects/{project_id}/nodes/{node_id}/start",
summary="Start a node",
@router.post("/{node_id}/start",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
async def start_node(project_id: UUID, node_id: UUID, start_data: dict):
responses=responses)
async def start_node(start_data: dict, node: Node = Depends(dep_node)):
"""
Start a node.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
await node.start(data=start_data)
@router.post("/projects/{project_id}/nodes/{node_id}/stop",
summary="Stop a node",
@router.post("/{node_id}/stop",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
async def stop_node(project_id: UUID, node_id: UUID):
responses=responses)
async def stop_node(node: Node = Depends(dep_node)):
"""
Stop a node.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
await node.stop()
@router.post("/projects/{project_id}/nodes/{node_id}/suspend",
summary="Suspend a node",
@router.post("/{node_id}/suspend",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
async def suspend_node(project_id: UUID, node_id: UUID):
responses=responses)
async def suspend_node(node: Node = Depends(dep_node)):
"""
Suspend a node.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
await node.suspend()
@router.post("/projects/{project_id}/nodes/{node_id}/reload",
summary="Reload a node",
@router.post("/{node_id}/reload",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
async def reload_node(project_id: UUID, node_id: UUID):
responses=responses)
async def reload_node(node: Node = Depends(dep_node)):
"""
Reload a node.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
await node.reload()
@router.get("/projects/{project_id}/nodes/{node_id}/links",
summary="List of all node links",
@router.get("/{node_id}/links",
response_model=List[schemas.Link],
response_description="List of links",
response_model_exclude_unset=True)
async def node_links(project_id: UUID, node_id: UUID):
async def get_node_links(node: Node = Depends(dep_node)):
"""
Return all the links connected to the node.
Return all the links connected to a node.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
links = []
for link in node.links:
links.append(link.__json__())
return links
@router.get("/projects/{project_id}/nodes/{node_id}/dynamips/auto_idlepc",
summary="Compute an Idle-PC",
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
async def auto_idlepc(project_id: UUID, node_id: UUID):
@router.get("/{node_id}/dynamips/auto_idlepc",
responses=responses)
async def auto_idlepc(node: Node = Depends(dep_node)):
"""
Compute an Idle-PC value for a Dynamips node
"""
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
return await node.dynamips_auto_idlepc()
@router.get("/projects/{project_id}/nodes/{node_id}/dynamips/idlepc_proposals",
summary="Compute list of Idle-PC values",
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
async def idlepc_proposals(project_id: UUID, node_id: UUID):
@router.get("/{node_id}/dynamips/idlepc_proposals",
responses=responses)
async def idlepc_proposals(node: Node = Depends(dep_node)):
"""
Compute a list of potential idle-pc values for a Dynamips node
"""
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
return await node.dynamips_idlepc_proposals()
@router.post("/projects/{project_id}/nodes/{node_id}/resize_disk",
summary="Resize a disk",
@router.post("/{node_id}/resize_disk",
status_code=status.HTTP_201_CREATED,
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
async def resize_disk(project_id: UUID, node_id: UUID, resize_data: dict):
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
responses=responses)
async def resize_disk(resize_data: dict, node: Node = Depends(dep_node)):
"""
Resize a disk image.
"""
await node.post("/resize_disk", **resize_data)
@router.get("/projects/{project_id}/nodes/{node_id}/files/{file_path:path}",
summary="Get a file in the node directory",
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
async def get_file(project_id: UUID, node_id: UUID, file_path: str):
@router.get("/{node_id}/files/{file_path:path}",
responses=responses)
async def get_file(file_path: str, node: Node = Depends(dep_node)):
"""
Return a file in the node directory
"""
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
path = force_unix_path(file_path)
# Raise error if user try to escape
@@ -339,18 +336,20 @@ async def get_file(project_id: UUID, node_id: UUID, file_path: str):
node_type = node.node_type
path = "/project-files/{}/{}/{}".format(node_type, node.id, path)
res = await node.compute.http_query("GET", "/projects/{project_id}/files{path}".format(project_id=project.id, path=path), timeout=None, raw=True)
res = await node.compute.http_query("GET", "/projects/{project_id}/files{path}".format(project_id=node.project.id, path=path),
timeout=None,
raw=True)
return Response(res.body, media_type="application/octet-stream")
@router.post("/projects/{project_id}/nodes/{node_id}/files/{file_path:path}",
summary="Write a file in the node directory",
@router.post("/{node_id}/files/{file_path:path}",
status_code=status.HTTP_201_CREATED,
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
async def post_file(project_id: UUID, node_id: UUID, file_path: str, request: Request):
responses=responses)
async def post_file(file_path: str, request: Request, node: Node = Depends(dep_node)):
"""
Write a file in the node directory.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
path = force_unix_path(file_path)
# Raise error if user try to escape
@@ -362,7 +361,10 @@ async def post_file(project_id: UUID, node_id: UUID, file_path: str, request: Re
data = await request.body() #FIXME: are we handling timeout or large files correctly?
await node.compute.http_query("POST", "/projects/{project_id}/files{path}".format(project_id=project.id, path=path), data=data, timeout=None, raw=True)
await node.compute.http_query("POST", "/projects/{project_id}/files{path}".format(project_id=node.project.id, path=path),
data=data,
timeout=None,
raw=True)
# @Route.get(
@@ -420,23 +422,20 @@ async def post_file(project_id: UUID, node_id: UUID, file_path: str, request: Re
# return ws
@router.post("/projects/{project_id}/nodes/console/reset",
@router.post("/console/reset",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
async def reset_console_all(project_id: UUID):
responses=responses)
async def reset_console_all(project: Project = Depends(dep_project)):
"""
Reset console for all nodes belonging to the project.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
await project.reset_console_all()
@router.post("/projects/{project_id}/nodes/{node_id}/console/reset",
@router.post("/{node_id}/console/reset",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project or node"}})
async def console_reset(project_id: UUID, node_id: UUID):
responses=responses)
async def console_reset(node: Node = Depends(dep_node)):
project = await Controller.instance().get_loaded_project(str(project_id))
node = project.get_node(str(node_id))
await node.post("/console/reset")#, request.json)
+100 -78
View File
@@ -19,28 +19,7 @@
API endpoints for projects.
"""
from fastapi import APIRouter, Request, Body, HTTPException, status, WebSocket, WebSocketDisconnect
from fastapi.encoders import jsonable_encoder
from fastapi.responses import StreamingResponse, FileResponse
from websockets.exceptions import WebSocketException
from typing import List
from pathlib import Path
from uuid import UUID
from gns3server.endpoints.schemas.common import ErrorMessage
from gns3server.endpoints import schemas
from gns3server.controller import Controller
from gns3server.controller.controller_error import ControllerError, ControllerForbiddenError
from gns3server.controller.import_project import import_project as import_controller_project
from gns3server.controller.export_project import export_project as export_controller_project
from gns3server.utils.asyncio import aiozipstream
from gns3server.config import Config
router = APIRouter()
import os
import aiohttp
import asyncio
import tempfile
import zipfile
@@ -50,17 +29,52 @@ import time
import logging
log = logging.getLogger()
from fastapi import APIRouter, Depends, Request, Body, HTTPException, status, WebSocket, WebSocketDisconnect
from fastapi.encoders import jsonable_encoder
from fastapi.responses import StreamingResponse, FileResponse
from websockets.exceptions import WebSocketException
from typing import List
from uuid import UUID
from gns3server.endpoints.schemas.common import ErrorMessage
from gns3server.endpoints import schemas
from gns3server.controller import Controller
from gns3server.controller.project import Project
from gns3server.controller.controller_error import ControllerError, ControllerForbiddenError
from gns3server.controller.import_project import import_project as import_controller_project
from gns3server.controller.export_project import export_project as export_controller_project
from gns3server.utils.asyncio import aiozipstream
from gns3server.config import Config
router = APIRouter()
responses = {
404: {"model": ErrorMessage, "description": "Could not find project"}
}
def dep_project(project_id: UUID):
"""
Dependency to retrieve a project.
"""
project = Controller.instance().get_project(str(project_id))
return project
CHUNK_SIZE = 1024 * 8 # 8KB
@router.post("/",
summary="Create project",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
response_model_exclude_unset=True,
responses={409: {"model": ErrorMessage, "description": "Could not create project"}})
async def create_project(project_data: schemas.ProjectCreate):
"""
Create a new project.
"""
controller = Controller.instance()
project = await controller.add_project(**jsonable_encoder(project_data, exclude_unset=True))
@@ -69,92 +83,105 @@ async def create_project(project_data: schemas.ProjectCreate):
@router.get("/",
summary="List of all projects",
response_model=List[schemas.Project],
response_description="List of projects",
response_model_exclude_unset=True)
def list_projects():
def get_projects():
"""
Return all projects.
"""
controller = Controller.instance()
return [p.__json__() for p in controller.projects.values()]
@router.get("/{project_id}",
summary="Get a project",
response_model=schemas.Project,
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
def get_project(project_id: UUID):
responses=responses)
def get_project(project: Project = Depends(dep_project)):
"""
Return a project.
"""
controller = Controller.instance()
project = controller.get_project(str(project_id))
return project.__json__()
@router.put("/{project_id}",
summary="Update a project",
response_model=schemas.Project,
response_model_exclude_unset=True,
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
async def update_project(project_id: UUID, project_data: schemas.ProjectUpdate):
responses=responses)
async def update_project(project_data: schemas.ProjectUpdate, project: Project = Depends(dep_project)):
"""
Update a project.
"""
controller = Controller.instance()
project = controller.get_project(str(project_id))
await project.update(**jsonable_encoder(project_data, exclude_unset=True))
return project.__json__()
@router.delete("/{project_id}",
summary="Delete a project",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
async def delete_project(project_id: UUID):
responses=responses)
async def delete_project(project: Project = Depends(dep_project)):
"""
Delete a project.
"""
controller = Controller.instance()
project = controller.get_project(str(project_id))
await project.delete()
controller.remove_project(project)
@router.get("/{project_id}/stats",
summary="Get a project statistics",
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
def get_project_stats(project_id: UUID):
responses=responses)
def get_project_stats(project: Project = Depends(dep_project)):
"""
Return a project statistics.
"""
controller = Controller.instance()
project = controller.get_project(str(project_id))
return project.stats()
@router.post("/{project_id}/close",
summary="Close a project",
status_code=status.HTTP_204_NO_CONTENT,
responses={409: {"model": ErrorMessage, "description": "Could not create project"}})
async def close_project(project_id: UUID):
responses={
**responses,
409: {"model": ErrorMessage, "description": "Could not close project"}
})
async def close_project(project: Project = Depends(dep_project)):
"""
Close a project.
"""
controller = Controller.instance()
project = controller.get_project(str(project_id))
await project.close()
@router.post("/{project_id}/open",
summary="Open a project",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
responses={409: {"model": ErrorMessage, "description": "Could not create project"}})
async def open_project(project_id: UUID):
responses={
**responses,
409: {"model": ErrorMessage, "description": "Could not open project"}
})
async def open_project(project: Project = Depends(dep_project)):
"""
Open a project.
"""
controller = Controller.instance()
project = controller.get_project(str(project_id))
await project.open()
return project.__json__()
@router.post("/load",
summary="Open a project (local server only)",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
responses={409: {"model": ErrorMessage, "description": "Could not load project"}})
responses={
**responses,
409: {"model": ErrorMessage, "description": "Could not load project"}
})
async def load_project(path: str = Body(..., embed=True)):
"""
Load a project (local server only).
"""
controller = Controller.instance()
config = Config.instance()
@@ -224,9 +251,8 @@ async def notification_ws(project_id: UUID, websocket: WebSocket):
@router.get("/{project_id}/export",
summary="Export project",
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
async def export_project(project_id: UUID,
responses=responses)
async def export_project(project: Project = Depends(dep_project),
include_snapshots: bool = False,
include_images: bool = False,
reset_mac_addresses: bool = False,
@@ -235,9 +261,6 @@ async def export_project(project_id: UUID,
Export a project as a portable archive.
"""
controller = Controller.instance()
project = controller.get_project(str(project_id))
compression_query = compression.lower()
if compression_query == "zip":
compression = zipfile.ZIP_DEFLATED
@@ -277,10 +300,9 @@ async def export_project(project_id: UUID,
@router.post("/{project_id}/import",
summary="Import a project",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
responses=responses)
async def import_project(project_id: UUID, request: Request):
"""
Import a project from a portable archive.
@@ -319,15 +341,16 @@ async def import_project(project_id: UUID, request: Request):
@router.post("/{project_id}/duplicate",
summary="Duplicate a project",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
responses={404: {"model": ErrorMessage, "description": "Could not find project"},
409: {"model": ErrorMessage, "description": "Could not duplicate project"}})
async def duplicate(project_id: UUID, project_data: schemas.ProjectDuplicate):
controller = Controller.instance()
project = await controller.get_loaded_project(str(project_id))
responses={
**responses,
409: {"model": ErrorMessage, "description": "Could not duplicate project"}
})
async def duplicate(project_data: schemas.ProjectDuplicate, project: Project = Depends(dep_project)):
"""
Duplicate a project.
"""
if project_data.path:
config = Config.instance()
@@ -343,13 +366,11 @@ async def duplicate(project_id: UUID, project_data: schemas.ProjectDuplicate):
@router.get("/{project_id}/files/{file_path:path}")
async def get_file(project_id: UUID, file_path: str):
async def get_file(file_path: str, project: Project = Depends(dep_project)):
"""
Get a file from a project.
Return a file from a project.
"""
controller = Controller.instance()
project = await controller.get_loaded_project(str(project_id))
path = os.path.normpath(file_path).strip('/')
# Raise error if user try to escape
@@ -365,10 +386,11 @@ async def get_file(project_id: UUID, file_path: str):
@router.post("/{project_id}/files/{file_path:path}",
status_code=status.HTTP_204_NO_CONTENT)
async def write_file(project_id: UUID, file_path: str, request: Request):
async def write_file(file_path: str, request: Request, project: Project = Depends(dep_project)):
"""
Write a file from a project.
"""
controller = Controller.instance()
project = await controller.get_loaded_project(str(project_id))
path = os.path.normpath(file_path).strip("/")
# Raise error if user try to escape
+34 -28
View File
@@ -19,75 +19,81 @@
API endpoints for snapshots.
"""
from fastapi import APIRouter, status
import logging
log = logging.getLogger()
from fastapi import APIRouter, Depends, status
from typing import List
from uuid import UUID
from gns3server.controller.project import Project
from gns3server.endpoints.schemas.common import ErrorMessage
from gns3server.endpoints import schemas
from gns3server.controller import Controller
router = APIRouter()
import logging
log = logging.getLogger()
responses = {
404: {"model": ErrorMessage, "description": "Could not find project or snapshot"}
}
@router.post("/projects/{project_id}/snapshots",
def dep_project(project_id: UUID):
"""
Dependency to retrieve a project.
"""
project = Controller.instance().get_project(str(project_id))
return project
@router.post("/",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Snapshot,
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
async def create_snapshot(project_id: UUID, snapshot_data: schemas.SnapshotCreate):
responses=responses)
async def create_snapshot(snapshot_data: schemas.SnapshotCreate, project: Project = Depends(dep_project)):
"""
Create a new snapshot of the project.
Create a new snapshot of a project.
"""
controller = Controller.instance()
project = controller.get_project(str(project_id))
snapshot = await project.snapshot(snapshot_data.name)
return snapshot.__json__()
@router.get("/projects/{project_id}/snapshots",
@router.get("/",
response_model=List[schemas.Snapshot],
response_description="List of snapshots",
response_model_exclude_unset=True,
responses={404: {"model": ErrorMessage, "description": "Could not find project"}})
def list_snapshots(project_id: UUID):
responses=responses)
def get_snapshots(project: Project = Depends(dep_project)):
"""
Return a list of snapshots belonging to the project.
Return all snapshots belonging to a given project.
"""
controller = Controller.instance()
project = controller.get_project(str(project_id))
snapshots = [s for s in project.snapshots.values()]
return [s.__json__() for s in sorted(snapshots, key=lambda s: (s.created_at, s.name))]
@router.delete("/projects/{project_id}/snapshots/{snapshot_id}",
@router.delete("/{snapshot_id}",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find project or snapshot"}})
async def delete_snapshot(project_id: UUID, snapshot_id: UUID):
responses=responses)
async def delete_snapshot(snapshot_id: UUID, project: Project = Depends(dep_project)):
"""
Delete a snapshot belonging to the project.
Delete a snapshot.
"""
controller = Controller.instance()
project = controller.get_project(str(project_id))
await project.delete_snapshot(str(snapshot_id))
@router.post("/projects/{project_id}/snapshots/{snapshot_id}/restore",
@router.post("/{snapshot_id}/restore",
status_code=status.HTTP_201_CREATED,
response_model=schemas.Project,
responses={404: {"model": ErrorMessage, "description": "Could not find project or snapshot"}})
async def restore_snapshot(project_id: UUID, snapshot_id: UUID):
responses=responses)
async def restore_snapshot(snapshot_id: UUID, project: Project = Depends(dep_project)):
"""
Restore a snapshot from the project.
Restore a snapshot.
"""
controller = Controller.instance()
project = controller.get_project(str(project_id))
snapshot = project.get_snapshot(str(snapshot_id))
project = await snapshot.restore()
return project.__json__()
+8 -6
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 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
@@ -20,9 +20,8 @@ API endpoints for symbols.
"""
import os
import shutil
from fastapi import APIRouter, Request, status, File, UploadFile
from fastapi import APIRouter, Request, status
from fastapi.responses import FileResponse
from gns3server.controller import Controller
@@ -37,7 +36,7 @@ router = APIRouter()
@router.get("/")
def list_symbols():
def get_symbols():
controller = Controller.instance()
return controller.symbols.list()
@@ -46,6 +45,9 @@ def list_symbols():
@router.get("/{symbol_id:path}/raw",
responses={404: {"model": ErrorMessage, "description": "Could not find symbol"}})
async def get_symbol(symbol_id: str):
"""
Download a symbol file.
"""
controller = Controller.instance()
try:
@@ -76,9 +78,9 @@ async def upload_symbol(symbol_id: str, request: Request):
@router.get("/default_symbols")
def list_default_symbols():
def get_default_symbols():
"""
Return list of default symbols.
Return all default symbols.
"""
controller = Controller.instance()
+33 -9
View File
@@ -22,6 +22,9 @@ API endpoints for templates.
import hashlib
import json
import logging
log = logging.getLogger(__name__)
from fastapi import APIRouter, Request, Response, HTTPException, status
from fastapi.encoders import jsonable_encoder
from typing import Union, List
@@ -33,8 +36,10 @@ from gns3server.controller import Controller
router = APIRouter()
import logging
log = logging.getLogger(__name__)
responses = {
404: {"model": ErrorMessage, "description": "Could not find template"}
}
#template_create_models = Union[schemas.VPCSTemplateCreate, schemas.CloudTemplateCreate, schemas.IOUTemplateCreate]
#template_update_models = Union[schemas.VPCSTemplateUpdate, schemas.CloudTemplateUpdate, schemas.IOUTemplateUpdate]
@@ -45,6 +50,9 @@ log = logging.getLogger(__name__)
status_code=status.HTTP_201_CREATED,
response_model=schemas.Template)
def create_template(template_data: schemas.TemplateCreate):
"""
Create a new template.
"""
controller = Controller.instance()
template = controller.template_manager.add_template(jsonable_encoder(template_data, exclude_unset=True))
@@ -54,11 +62,13 @@ def create_template(template_data: schemas.TemplateCreate):
@router.get("/templates/{template_id}",
summary="List of all nodes",
response_model=schemas.Template,
response_model_exclude_unset=True,
responses={404: {"model": ErrorMessage, "description": "Could not find template"}})
responses=responses)
def get_template(template_id: UUID, request: Request, response: Response):
"""
Return a template.
"""
request_etag = request.headers.get("If-None-Match", "")
controller = Controller.instance()
@@ -75,8 +85,11 @@ def get_template(template_id: UUID, request: Request, response: Response):
@router.put("/templates/{template_id}",
response_model=schemas.Template,
response_model_exclude_unset=True,
responses={404: {"model": ErrorMessage, "description": "Template not found"}})
responses=responses)
def update_template(template_id: UUID, template_data: schemas.TemplateUpdate):
"""
Update a template.
"""
controller = Controller.instance()
template = controller.template_manager.get_template(str(template_id))
@@ -86,8 +99,11 @@ def update_template(template_id: UUID, template_data: schemas.TemplateUpdate):
@router.delete("/templates/{template_id}",
status_code=status.HTTP_204_NO_CONTENT,
responses={404: {"model": ErrorMessage, "description": "Could not find template"}})
responses=responses)
def delete_template(template_id: UUID):
"""
Delete a template.
"""
controller = Controller.instance()
controller.template_manager.delete_template(str(template_id))
@@ -95,9 +111,11 @@ def delete_template(template_id: UUID):
@router.get("/templates",
response_model=List[schemas.Template],
response_description="List of templates",
response_model_exclude_unset=True)
def list_templates():
def get_templates():
"""
Return all templates.
"""
controller = Controller.instance()
return [c.__json__() for c in controller.template_manager.templates.values()]
@@ -106,8 +124,11 @@ def list_templates():
@router.post("/templates/{template_id}/duplicate",
response_model=schemas.Template,
status_code=status.HTTP_201_CREATED,
responses={404: {"model": ErrorMessage, "description": "Could not find template"}})
responses=responses)
async def duplicate_template(template_id: UUID):
"""
Duplicate a template.
"""
controller = Controller.instance()
template = controller.template_manager.duplicate_template(str(template_id))
@@ -119,6 +140,9 @@ async def duplicate_template(template_id: UUID):
status_code=status.HTTP_201_CREATED,
responses={404: {"model": ErrorMessage, "description": "Could not find project or template"}})
async def create_node_from_template(project_id: UUID, template_id: UUID, template_usage: schemas.TemplateUsage):
"""
Create a new node from a template.
"""
controller = Controller.instance()
project = controller.get_project(str(project_id))