mirror of
https://github.com/GNS3/gns3-server
synced 2024-12-01 04:38:12 +00:00
Add a custom version to an appliance
This commit is contained in:
parent
be473aaaf7
commit
a31e5615a4
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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')
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user