1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-11-25 01:38:08 +00:00

Fix validation issues and improve exceptions logs

This commit is contained in:
grossmj 2023-08-17 17:36:50 +10:00
parent ca48efa5be
commit e9e2dc2ca7
4 changed files with 33 additions and 23 deletions

View File

@ -34,7 +34,7 @@ router = APIRouter()
@router.get("/docker/images") @router.get("/docker/images")
async def get_docker_images() -> List[str]: async def get_docker_images() -> List[dict]:
""" """
Get all Docker images. Get all Docker images.
""" """

View File

@ -18,8 +18,8 @@
API routes for computes. API routes for computes.
""" """
from fastapi import APIRouter, Depends, Response, status from fastapi import APIRouter, Depends, status
from typing import List, Union, Optional from typing import Any, List, Union, Optional
from uuid import UUID from uuid import UUID
from gns3server.controller import Controller from gns3server.controller import Controller
@ -157,7 +157,7 @@ async def dynamips_autoidlepc(compute_id: Union[str, UUID], auto_idle_pc: schema
@router.get("/{compute_id}/{emulator}/{endpoint_path:path}", deprecated=True) @router.get("/{compute_id}/{emulator}/{endpoint_path:path}", deprecated=True)
async def forward_get(compute_id: Union[str, UUID], emulator: str, endpoint_path: str) -> dict: async def forward_get(compute_id: Union[str, UUID], emulator: str, endpoint_path: str) -> Any:
""" """
Forward a GET request to a compute. Forward a GET request to a compute.
Read the full compute API documentation for available routes. Read the full compute API documentation for available routes.
@ -169,7 +169,7 @@ async def forward_get(compute_id: Union[str, UUID], emulator: str, endpoint_path
@router.post("/{compute_id}/{emulator}/{endpoint_path:path}", deprecated=True) @router.post("/{compute_id}/{emulator}/{endpoint_path:path}", deprecated=True)
async def forward_post(compute_id: Union[str, UUID], emulator: str, endpoint_path: str, compute_data: dict) -> dict: async def forward_post(compute_id: Union[str, UUID], emulator: str, endpoint_path: str, compute_data: dict) -> Any:
""" """
Forward a POST request to a compute. Forward a POST request to a compute.
Read the full compute API documentation for available routes. Read the full compute API documentation for available routes.
@ -180,7 +180,7 @@ async def forward_post(compute_id: Union[str, UUID], emulator: str, endpoint_pat
@router.put("/{compute_id}/{emulator}/{endpoint_path:path}", deprecated=True) @router.put("/{compute_id}/{emulator}/{endpoint_path:path}", deprecated=True)
async def forward_put(compute_id: Union[str, UUID], emulator: str, endpoint_path: str, compute_data: dict) -> dict: async def forward_put(compute_id: Union[str, UUID], emulator: str, endpoint_path: str, compute_data: dict) -> Any:
""" """
Forward a PUT request to a compute. Forward a PUT request to a compute.
Read the full compute API documentation for available routes. Read the full compute API documentation for available routes.

View File

@ -21,9 +21,10 @@ FastAPI app
import time import time
from fastapi import FastAPI, Request, HTTPException from fastapi import FastAPI, Request, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from uvicorn.main import Server as UvicornServer from uvicorn.main import Server as UvicornServer
@ -87,54 +88,54 @@ UvicornServer.handle_exit = handle_exit
@app.exception_handler(ControllerError) @app.exception_handler(ControllerError)
async def controller_error_handler(request: Request, exc: ControllerError): async def controller_error_handler(request: Request, exc: ControllerError):
log.error(f"Controller error: {exc}") log.error(f"Controller error in {request.url.path} ({request.method}): {exc}")
return JSONResponse( return JSONResponse(
status_code=409, status_code=status.HTTP_409_CONFLICT,
content={"message": str(exc)}, content={"message": str(exc)},
) )
@app.exception_handler(ControllerTimeoutError) @app.exception_handler(ControllerTimeoutError)
async def controller_timeout_error_handler(request: Request, exc: ControllerTimeoutError): async def controller_timeout_error_handler(request: Request, exc: ControllerTimeoutError):
log.error(f"Controller timeout error: {exc}") log.error(f"Controller timeout error in {request.url.path} ({request.method}): {exc}")
return JSONResponse( return JSONResponse(
status_code=408, status_code=status.HTTP_408_REQUEST_TIMEOUT,
content={"message": str(exc)}, content={"message": str(exc)},
) )
@app.exception_handler(ControllerUnauthorizedError) @app.exception_handler(ControllerUnauthorizedError)
async def controller_unauthorized_error_handler(request: Request, exc: ControllerUnauthorizedError): async def controller_unauthorized_error_handler(request: Request, exc: ControllerUnauthorizedError):
log.error(f"Controller unauthorized error: {exc}") log.error(f"Controller unauthorized error in {request.url.path} ({request.method}): {exc}")
return JSONResponse( return JSONResponse(
status_code=401, status_code=status.HTTP_401_UNAUTHORIZED,
content={"message": str(exc)}, content={"message": str(exc)},
) )
@app.exception_handler(ControllerForbiddenError) @app.exception_handler(ControllerForbiddenError)
async def controller_forbidden_error_handler(request: Request, exc: ControllerForbiddenError): async def controller_forbidden_error_handler(request: Request, exc: ControllerForbiddenError):
log.error(f"Controller forbidden error: {exc}") log.error(f"Controller forbidden error in {request.url.path} ({request.method}): {exc}")
return JSONResponse( return JSONResponse(
status_code=403, status_code=status.HTTP_403_FORBIDDEN,
content={"message": str(exc)}, content={"message": str(exc)},
) )
@app.exception_handler(ControllerNotFoundError) @app.exception_handler(ControllerNotFoundError)
async def controller_not_found_error_handler(request: Request, exc: ControllerNotFoundError): async def controller_not_found_error_handler(request: Request, exc: ControllerNotFoundError):
log.error(f"Controller not found error: {exc}") log.error(f"Controller not found error in {request.url.path} ({request.method}): {exc}")
return JSONResponse( return JSONResponse(
status_code=404, status_code=status.HTTP_404_NOT_FOUND,
content={"message": str(exc)}, content={"message": str(exc)},
) )
@app.exception_handler(ControllerBadRequestError) @app.exception_handler(ControllerBadRequestError)
async def controller_bad_request_error_handler(request: Request, exc: ControllerBadRequestError): async def controller_bad_request_error_handler(request: Request, exc: ControllerBadRequestError):
log.error(f"Controller bad request error: {exc}") log.error(f"Controller bad request error in {request.url.path} ({request.method}): {exc}")
return JSONResponse( return JSONResponse(
status_code=400, status_code=status.HTTP_400_BAD_REQUEST,
content={"message": str(exc)}, content={"message": str(exc)},
) )
@ -143,7 +144,7 @@ async def controller_bad_request_error_handler(request: Request, exc: Controller
async def compute_conflict_error_handler(request: Request, exc: ComputeConflictError): async def compute_conflict_error_handler(request: Request, exc: ComputeConflictError):
log.error(f"Controller received error from compute for request '{exc.url()}': {exc}") log.error(f"Controller received error from compute for request '{exc.url()}': {exc}")
return JSONResponse( return JSONResponse(
status_code=409, status_code=status.HTTP_409_CONFLICT,
content={"message": str(exc)}, content={"message": str(exc)},
) )
@ -160,12 +161,21 @@ async def http_exception_handler(request: Request, exc: HTTPException):
@app.exception_handler(SQLAlchemyError) @app.exception_handler(SQLAlchemyError)
async def sqlalchemry_error_handler(request: Request, exc: SQLAlchemyError): async def sqlalchemry_error_handler(request: Request, exc: SQLAlchemyError):
log.error(f"Controller database error: {exc}") log.error(f"Controller database error in {request.url.path} ({request.method}): {exc}")
return JSONResponse( return JSONResponse(
status_code=500, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={"message": "Database error detected, please check logs to find details"}, content={"message": "Database error detected, please check logs to find details"},
) )
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
log.error(f"Request validation error in {request.url.path} ({request.method}): {exc}")
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={"message": str(exc)}
)
# FIXME: do not use this middleware since it creates issue when using StreamingResponse # FIXME: do not use this middleware since it creates issue when using StreamingResponse
# see https://starlette-context.readthedocs.io/en/latest/middleware.html#why-are-there-two-middlewares-that-do-the-same-thing # see https://starlette-context.readthedocs.io/en/latest/middleware.html#why-are-there-two-middlewares-that-do-the-same-thing

View File

@ -1,5 +1,5 @@
uvicorn==0.22.0 # v0.22.0 is the last to support Python 3.7 uvicorn==0.22.0 # v0.22.0 is the last to support Python 3.7
fastapi==0.101.0 fastapi==0.101.1
python-multipart==0.0.6 python-multipart==0.0.6
websockets==11.0.3 websockets==11.0.3
aiohttp>=3.8.5,<3.9 aiohttp>=3.8.5,<3.9