Handle creating Qemu disk images and resizing

This commit is contained in:
grossmj
2022-04-07 16:21:47 +08:00
parent 888c773dc0
commit fda2a37b98
20 changed files with 701 additions and 472 deletions

View File

@ -51,6 +51,11 @@ from . import virtualbox_nodes
from . import vmware_nodes
from . import vpcs_nodes
import logging
log = logging.getLogger(__name__)
compute_api = FastAPI(
title="GNS3 compute API",
dependencies=[Depends(compute_authentication)],
@ -63,6 +68,7 @@ compute_api.state.controller_host = None
@compute_api.exception_handler(ComputeError)
async def controller_error_handler(request: Request, exc: ComputeError):
log.error(f"Compute error: {exc}")
return JSONResponse(
status_code=409,
content={"message": str(exc)},
@ -71,6 +77,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):
log.error(f"Compute timeout error: {exc}")
return JSONResponse(
status_code=408,
content={"message": str(exc)},
@ -79,6 +86,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):
log.error(f"Compute unauthorized error: {exc}")
return JSONResponse(
status_code=401,
content={"message": str(exc)},
@ -87,6 +95,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):
log.error(f"Compute forbidden error: {exc}")
return JSONResponse(
status_code=403,
content={"message": str(exc)},
@ -95,6 +104,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):
log.error(f"Compute not found error: {exc}")
return JSONResponse(
status_code=404,
content={"message": str(exc)},
@ -103,6 +113,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):
log.error(f"Compute GNS3 VM error: {exc}")
return JSONResponse(
status_code=409,
content={"message": str(exc)},
@ -111,6 +122,7 @@ async def controller_error_handler(request: Request, exc: GNS3VMError):
@compute_api.exception_handler(ImageMissingError)
async def image_missing_error_handler(request: Request, exc: ImageMissingError):
log.error(f"Compute image missing error: {exc}")
return JSONResponse(
status_code=409,
content={"message": str(exc), "image": exc.image, "exception": exc.__class__.__name__},
@ -119,6 +131,7 @@ async def image_missing_error_handler(request: Request, exc: ImageMissingError):
@compute_api.exception_handler(NodeError)
async def node_error_handler(request: Request, exc: NodeError):
log.error(f"Compute node error: {exc}")
return JSONResponse(
status_code=409,
content={"message": str(exc), "exception": exc.__class__.__name__},
@ -127,6 +140,7 @@ async def node_error_handler(request: Request, exc: NodeError):
@compute_api.exception_handler(UbridgeError)
async def ubridge_error_handler(request: Request, exc: UbridgeError):
log.error(f"Compute uBridge error: {exc}")
return JSONResponse(
status_code=409,
content={"message": str(exc), "exception": exc.__class__.__name__},

View File

@ -144,55 +144,6 @@ async def get_qemu_capabilities() -> dict:
return capabilities
@router.post(
"/qemu/img",
status_code=status.HTTP_204_NO_CONTENT,
responses={403: {"model": schemas.ErrorMessage, "description": "Forbidden to create Qemu image"}},
)
async def create_qemu_image(image_data: schemas.QemuImageCreate) -> Response:
"""
Create a Qemu image.
"""
#FIXME: move to controller
raise NotImplementedError()
# Raise error if user try to escape
#if not is_safe_path(image_data.path, project.path):
# raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
await Qemu.instance().create_disk(
image_data.qemu_img,
image_data.path,
jsonable_encoder(image_data, exclude_unset=True, exclude={"qemu_img", "path"})
)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.put(
"/qemu/img",
status_code=status.HTTP_204_NO_CONTENT,
responses={403: {"model": schemas.ErrorMessage, "description": "Forbidden to update Qemu image"}},
)
async def update_qemu_image(image_data: schemas.QemuImageUpdate) -> Response:
"""
Update a Qemu image.
"""
#FIXME: move to controller
raise NotImplementedError()
# Raise error if user try to escape
#if not is_safe_path(image_data.path, project.path):
# raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
if image_data.extend:
await Qemu.instance().resize_disk(image_data.qemu_img, image_data.path, image_data.extend)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/virtualbox/vms", response_model=List[dict])
async def get_virtualbox_vms() -> List[dict]:

View File

@ -26,10 +26,10 @@ from fastapi.responses import StreamingResponse
from uuid import UUID
from gns3server import schemas
from gns3server.compute.project_manager import ProjectManager
from gns3server.compute.qemu import Qemu
from gns3server.compute.qemu.qemu_vm import QemuVM
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project or Qemu node"}}
router = APIRouter(responses=responses)
@ -126,10 +126,39 @@ async def duplicate_qemu_node(
return new_node.asdict()
@router.post("/{node_id}/resize_disk", status_code=status.HTTP_204_NO_CONTENT)
async def resize_qemu_node_disk(node_data: schemas.QemuDiskResize, node: QemuVM = Depends(dep_node)) -> Response:
@router.post(
"/{node_id}/disk_image/{disk_name}",
status_code=status.HTTP_204_NO_CONTENT
)
async def create_qemu_disk_image(
disk_name: str,
disk_data: schemas.QemuDiskImageCreate,
node: QemuVM = Depends(dep_node)
) -> Response:
"""
Create a Qemu disk image.
"""
await node.resize_disk(node_data.drive_name, node_data.extend)
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(
"/{node_id}/disk_image/{disk_name}",
status_code=status.HTTP_204_NO_CONTENT
)
async def update_qemu_disk_image(
disk_name: str,
disk_data: schemas.QemuDiskImageUpdate,
node: QemuVM = Depends(dep_node)
) -> Response:
"""
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)