1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-11-28 11:18:11 +00:00

Add a custom version to an appliance

This commit is contained in:
grossmj 2021-10-19 15:15:10 +10:30
parent be473aaaf7
commit a31e5615a4
4 changed files with 63 additions and 8 deletions

View File

@ -26,7 +26,12 @@ from uuid import UUID
from gns3server import schemas from gns3server import schemas
from gns3server.controller import Controller from gns3server.controller import Controller
from gns3server.controller.controller_error import ControllerNotFoundError from gns3server.controller.controller_error import (
ControllerError,
ControllerBadRequestError,
ControllerNotFoundError
)
from gns3server.db.repositories.images import ImagesRepository from gns3server.db.repositories.images import ImagesRepository
from gns3server.db.repositories.templates import TemplatesRepository from gns3server.db.repositories.templates import TemplatesRepository
from gns3server.db.repositories.rbac import RbacRepository from gns3server.db.repositories.rbac import RbacRepository
@ -68,6 +73,31 @@ def get_appliance(appliance_id: UUID) -> schemas.Appliance:
return appliance.asdict() return appliance.asdict()
@router.post("/{appliance_id}/version", status_code=status.HTTP_201_CREATED)
def add_appliance_version(appliance_id: UUID, appliance_version: schemas.ApplianceVersion) -> schemas.Appliance:
"""
Add a version to an appliance
"""
controller = Controller.instance()
appliance = controller.appliance_manager.appliances.get(str(appliance_id))
if not appliance:
raise ControllerNotFoundError(message=f"Could not find appliance '{appliance_id}'")
if not appliance.versions:
raise ControllerBadRequestError(message=f"Appliance '{appliance_id}' do not have versions")
if not appliance_version.images:
raise ControllerBadRequestError(message=f"Version '{appliance_version.name}' must contain images")
for version in appliance.versions:
if version.get("name") == appliance_version.name:
raise ControllerError(message=f"Appliance '{appliance_id}' already has version '{appliance_version.name}'")
appliance.versions.append(appliance_version.dict(exclude_unset=True))
return appliance.asdict()
@router.post("/{appliance_id}/install", status_code=status.HTTP_204_NO_CONTENT) @router.post("/{appliance_id}/install", status_code=status.HTTP_204_NO_CONTENT)
async def install_appliance( async def install_appliance(
appliance_id: UUID, appliance_id: UUID,

View File

@ -24,7 +24,7 @@ from .controller.links import LinkCreate, LinkUpdate, Link
from .controller.computes import ComputeCreate, ComputeUpdate, AutoIdlePC, Compute from .controller.computes import ComputeCreate, ComputeUpdate, AutoIdlePC, Compute
from .controller.templates import TemplateCreate, TemplateUpdate, TemplateUsage, Template from .controller.templates import TemplateCreate, TemplateUpdate, TemplateUsage, Template
from .controller.images import Image, ImageType from .controller.images import Image, ImageType
from .controller.appliances import Appliance from .controller.appliances import ApplianceVersion, Appliance
from .controller.drawings import Drawing from .controller.drawings import Drawing
from .controller.gns3vm import GNS3VM from .controller.gns3vm import GNS3VM
from .controller.nodes import NodeCreate, NodeUpdate, NodeDuplicate, NodeCapture, Node from .controller.nodes import NodeCreate, NodeUpdate, NodeDuplicate, NodeCapture, Node

View File

@ -317,7 +317,7 @@ class Compression(Enum):
field_7z = '7z' field_7z = '7z'
class Image(BaseModel): class ApplianceImage(BaseModel):
filename: str = Field(..., title='Filename') filename: str = Field(..., title='Filename')
version: str = Field(..., title='Version of the file') version: str = Field(..., title='Version of the file')
@ -335,7 +335,7 @@ class Image(BaseModel):
) )
class Images(BaseModel): class ApplianceVersionImages(BaseModel):
kernel_image: Optional[str] = Field(None, title='Kernel image') kernel_image: Optional[str] = Field(None, title='Kernel image')
initrd: Optional[str] = Field(None, title='Initrd disk image') initrd: Optional[str] = Field(None, title='Initrd disk image')
@ -348,11 +348,11 @@ class Images(BaseModel):
cdrom_image: Optional[str] = Field(None, title='cdrom image') cdrom_image: Optional[str] = Field(None, title='cdrom image')
class Version(BaseModel): class ApplianceVersion(BaseModel):
name: str = Field(..., title='Name of the version') name: str = Field(..., title='Name of the version')
idlepc: Optional[str] = Field(None, regex='^0x[0-9a-f]{8}') idlepc: Optional[str] = Field(None, regex='^0x[0-9a-f]{8}')
images: Optional[Images] = Field(None, title='Images used for this version') images: Optional[ApplianceVersionImages] = Field(None, title='Images used for this version')
class DynamipsSlot(Enum): class DynamipsSlot(Enum):
@ -460,5 +460,5 @@ class Appliance(BaseModel):
iou: Optional[Iou] = Field(None, title='IOU specific options') iou: Optional[Iou] = Field(None, title='IOU specific options')
dynamips: Optional[Dynamips] = Field(None, title='Dynamips specific options') dynamips: Optional[Dynamips] = Field(None, title='Dynamips specific options')
qemu: Optional[Qemu] = Field(None, title='Qemu specific options') qemu: Optional[Qemu] = Field(None, title='Qemu specific options')
images: Optional[List[Image]] = Field(None, title='Images for this appliance') images: Optional[List[ApplianceImage]] = Field(None, title='Images for this appliance')
versions: Optional[List[Version]] = Field(None, title='Versions of the appliance') versions: Optional[List[ApplianceVersion]] = Field(None, title='Versions of the appliance')

View File

@ -66,3 +66,28 @@ class TestApplianceRoutes:
appliance_id = "1cfdf900-7c30-4cb7-8f03-3f61d2581633" # Empty VM appliance appliance_id = "1cfdf900-7c30-4cb7-8f03-3f61d2581633" # Empty VM appliance
response = await client.post(app.url_path_for("install_appliance", appliance_id=appliance_id)) response = await client.post(app.url_path_for("install_appliance", appliance_id=appliance_id))
assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.status_code == status.HTTP_400_BAD_REQUEST
async def test_add_version_appliance(self, app: FastAPI, client: AsyncClient) -> None:
appliance_id = "1cfdf900-7c30-4cb7-8f03-3f61d2581633" # Empty VM appliance
new_version = {
"name": "99G",
"images": {
"hda_disk_image": "empty99G.qcow2"
}
}
response = await client.post(app.url_path_for("add_appliance_version", appliance_id=appliance_id), json=new_version)
assert response.status_code == status.HTTP_201_CREATED
assert new_version in response.json()["versions"]
async def test_add_existing_version_appliance(self, app: FastAPI, client: AsyncClient) -> None:
appliance_id = "1cfdf900-7c30-4cb7-8f03-3f61d2581633" # Empty VM appliance
new_version = {
"name": "8G",
"images": {
"hda_disk_image": "empty8G.qcow2"
}
}
response = await client.post(app.url_path_for("add_appliance_version", appliance_id=appliance_id), json=new_version)
assert response.status_code == status.HTTP_409_CONFLICT