Start refactoring for images management

This commit is contained in:
grossmj committed 2021-06-06 16:52:47 +09:30
1 parent f64b5cd9b6
commit 515bd50261
16 files changed
+594 -30

No files matched your search

@@ -28,6 +28,7 @@ from . import projects
from . import snapshots
from . import symbols
from . import templates
from . import images
from . import users
from . import groups
from . import roles
@@ -61,9 +62,17 @@ router.include_router(
tags=["Permissions"]
)
router.include_router(
images.router,
dependencies=[Depends(get_current_active_user)],
prefix="/images",
tags=["Images"]
)
router.include_router(
templates.router,
dependencies=[Depends(get_current_active_user)],
prefix="/templates",
tags=["Templates"]
)
+2 -1
View File
@@ -25,6 +25,7 @@ from typing import List
from gns3server import schemas
from gns3server.controller.controller_error import (
ControllerError,
ControllerBadRequestError,
ControllerNotFoundError,
ControllerForbiddenError,
@@ -126,7 +127,7 @@ async def delete_user_group(
success = await users_repo.delete_user_group(user_group_id)
if not success:
raise ControllerNotFoundError(f"User group '{user_group_id}' could not be deleted")
raise ControllerError(f"User group '{user_group_id}' could not be deleted")
@router.get("/{user_group_id}/members", response_model=List[schemas.User])
+122
View File
@@ -0,0 +1,122 @@
#
# Copyright (C) 2021 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
API routes for images.
"""
import os
import logging
import urllib.parse
from fastapi import APIRouter, Request, Depends, status
from typing import List
from gns3server import schemas
from gns3server.utils.images import InvalidImageError, default_images_directory, write_image
from gns3server.db.repositories.images import ImagesRepository
from gns3server.controller.controller_error import (
ControllerError,
ControllerNotFoundError,
ControllerForbiddenError,
ControllerBadRequestError
)
from .dependencies.database import get_repository
log = logging.getLogger(__name__)
router = APIRouter()
@router.get("")
async def get_images(
images_repo: ImagesRepository = Depends(get_repository(ImagesRepository)),
) -> List[schemas.Image]:
"""
Return all images.
"""
return await images_repo.get_images()
@router.post("/upload/{image_name}", response_model=schemas.Image, status_code=status.HTTP_201_CREATED)
async def upload_image(
image_name: str,
image_type: schemas.ImageType,
request: Request,
images_repo: ImagesRepository = Depends(get_repository(ImagesRepository)),
) -> schemas.Image:
"""
Upload an image.
"""
image_name = urllib.parse.unquote(image_name)
directory = default_images_directory(image_type)
path = os.path.abspath(os.path.join(directory, image_name))
if os.path.commonprefix([directory, path]) != directory:
raise ControllerForbiddenError(f"Could not write image: {image_name}, '{path}' is forbidden")
if await images_repo.get_image(image_name):
raise ControllerBadRequestError(f"Image '{image_name}' already exists")
try:
image = await write_image(image_name, image_type, path, request.stream(), images_repo)
except (OSError, InvalidImageError) as e:
raise ControllerError(f"Could not save {image_type} image '{image_name}': {e}")
return image
@router.get("/{image_name}", response_model=schemas.Image)
async def get_image(
image_name: str,
images_repo: ImagesRepository = Depends(get_repository(ImagesRepository)),
) -> schemas.Image:
"""
Return an image.
"""
image = await images_repo.get_image(image_name)
if not image:
raise ControllerNotFoundError(f"Image '{image_name}' not found")
return image
@router.delete("/{image_name}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_image(
image_name: str,
images_repo: ImagesRepository = Depends(get_repository(ImagesRepository)),
) -> None:
"""
Delete an image.
"""
image = await images_repo.get_image(image_name)
if not image:
raise ControllerNotFoundError(f"Image '{image_name}' not found")
if await images_repo.get_image_templates(image.id):
raise ControllerError(f"Image '{image_name}' is used by one or more templates")
try:
os.remove(image.path)
except OSError:
log.warning(f"Could not delete image file {image.path}")
success = await images_repo.delete_image(image_name)
if not success:
raise ControllerError(f"Image '{image_name}' could not be deleted")
@@ -25,6 +25,7 @@ from typing import List
from gns3server import schemas
from gns3server.controller.controller_error import (
ControllerError,
ControllerBadRequestError,
ControllerNotFoundError,
ControllerForbiddenError,
@@ -114,4 +115,4 @@ async def delete_permission(
success = await rbac_repo.delete_permission(permission_id)
if not success:
raise ControllerNotFoundError(f"Permission '{permission_id}' could not be deleted")
raise ControllerError(f"Permission '{permission_id}' could not be deleted")
+2 -1
View File
@@ -25,6 +25,7 @@ from typing import List
from gns3server import schemas
from gns3server.controller.controller_error import (
ControllerError,
ControllerBadRequestError,
ControllerNotFoundError,
ControllerForbiddenError,
@@ -119,7 +120,7 @@ async def delete_role(
success = await rbac_repo.delete_role(role_id)
if not success:
raise ControllerNotFoundError(f"Role '{role_id}' could not be deleted")
raise ControllerError(f"Role '{role_id}' could not be deleted")
@router.get("/{role_id}/permissions", response_model=List[schemas.Permission])
@@ -42,7 +42,7 @@ responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find
router = APIRouter(responses=responses)
@router.post("/templates", response_model=schemas.Template, status_code=status.HTTP_201_CREATED)
@router.post("", response_model=schemas.Template, status_code=status.HTTP_201_CREATED)
async def create_template(
template_create: schemas.TemplateCreate,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
@@ -59,7 +59,7 @@ async def create_template(
return template
@router.get("/templates/{template_id}", response_model=schemas.Template, response_model_exclude_unset=True)
@router.get("/{template_id}", response_model=schemas.Template, response_model_exclude_unset=True)
async def get_template(
template_id: UUID,
request: Request,
@@ -81,7 +81,7 @@ async def get_template(
return template
@router.put("/templates/{template_id}", response_model=schemas.Template, response_model_exclude_unset=True)
@router.put("/{template_id}", response_model=schemas.Template, response_model_exclude_unset=True)
async def update_template(
template_id: UUID,
template_update: schemas.TemplateUpdate,
@@ -94,10 +94,7 @@ async def update_template(
return await TemplatesService(templates_repo).update_template(template_id, template_update)
@router.delete(
"/templates/{template_id}",
status_code=status.HTTP_204_NO_CONTENT,
)
@router.delete("/{template_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_template(
template_id: UUID,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
@@ -111,7 +108,7 @@ async def delete_template(
await rbac_repo.delete_all_permissions_with_path(f"/templates/{template_id}")
@router.get("/templates", response_model=List[schemas.Template], response_model_exclude_unset=True)
@router.get("", response_model=List[schemas.Template], response_model_exclude_unset=True)
async def get_templates(
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
current_user: schemas.User = Depends(get_current_active_user),
@@ -138,7 +135,7 @@ async def get_templates(
return user_templates
@router.post("/templates/{template_id}/duplicate", response_model=schemas.Template, status_code=status.HTTP_201_CREATED)
@router.post("/{template_id}/duplicate", response_model=schemas.Template, status_code=status.HTTP_201_CREATED)
async def duplicate_template(
template_id: UUID, templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
current_user: schemas.User = Depends(get_current_active_user),
+2 -1
View File
@@ -26,6 +26,7 @@ from typing import List
from gns3server import schemas
from gns3server.controller.controller_error import (
ControllerError,
ControllerBadRequestError,
ControllerNotFoundError,
ControllerForbiddenError,
@@ -194,7 +195,7 @@ async def delete_user(
success = await users_repo.delete_user(user_id)
if not success:
raise ControllerNotFoundError(f"User '{user_id}' could not be deleted")
raise ControllerError(f"User '{user_id}' could not be deleted")
@router.get(