Add controller endpoints to get VirtualBox VMs, VMware VMs and Docker images

pull/2082/head
grossmj 2 years ago
parent 3b7dfe5929
commit 7d49b80e6b

@ -115,18 +115,50 @@ async def delete_compute(
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{compute_id}/{emulator}/images")
async def get_images(compute_id: Union[str, UUID], emulator: str) -> List[str]:
@router.get("/{compute_id}/docker/images", response_model=List[schemas.ComputeDockerImage])
async def docker_get_images(compute_id: Union[str, UUID]) -> List[schemas.ComputeDockerImage]:
"""
Return the list of images available on a compute for a given emulator type.
Get Docker images from a compute.
"""
compute = Controller.instance().get_compute(str(compute_id))
result = await compute.forward("GET", "docker", "images")
return result
@router.get("/{compute_id}/virtualbox/vms", response_model=List[schemas.ComputeVirtualBoxVM])
async def virtualbox_vms(compute_id: Union[str, UUID]) -> List[schemas.ComputeVirtualBoxVM]:
"""
Get VirtualBox VMs from a compute.
"""
compute = Controller.instance().get_compute(str(compute_id))
result = await compute.forward("GET", "virtualbox", "vms")
return result
@router.get("/{compute_id}/vmware/vms", response_model=List[schemas.ComputeVMwareVM])
async def vmware_vms(compute_id: Union[str, UUID]) -> List[schemas.ComputeVMwareVM]:
"""
Get VMware VMs from a compute.
"""
compute = Controller.instance().get_compute(str(compute_id))
result = await compute.forward("GET", "vmware", "vms")
return result
@router.post("/{compute_id}/dynamips/auto_idlepc")
async def dynamips_autoidlepc(compute_id: Union[str, UUID], auto_idle_pc: schemas.AutoIdlePC) -> str:
"""
Find a suitable Idle-PC value for a given IOS image. This may take a few minutes.
"""
controller = Controller.instance()
compute = controller.get_compute(str(compute_id))
return await compute.images(emulator)
return await controller.autoidlepc(str(compute_id), auto_idle_pc.platform, auto_idle_pc.image, auto_idle_pc.ram)
@router.get("/{compute_id}/{emulator}/{endpoint_path:path}")
@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:
"""
Forward a GET request to a compute.
@ -138,7 +170,7 @@ async def forward_get(compute_id: Union[str, UUID], emulator: str, endpoint_path
return result
@router.post("/{compute_id}/{emulator}/{endpoint_path:path}")
@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:
"""
Forward a POST request to a compute.
@ -149,7 +181,7 @@ async def forward_post(compute_id: Union[str, UUID], emulator: str, endpoint_pat
return await compute.forward("POST", emulator, endpoint_path, data=compute_data)
@router.put("/{compute_id}/{emulator}/{endpoint_path:path}")
@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:
"""
Forward a PUT request to a compute.
@ -158,13 +190,3 @@ async def forward_put(compute_id: Union[str, UUID], emulator: str, endpoint_path
compute = Controller.instance().get_compute(str(compute_id))
return await compute.forward("PUT", emulator, endpoint_path, data=compute_data)
@router.post("/{compute_id}/dynamips/auto_idlepc")
async def dynamips_autoidlepc(compute_id: Union[str, UUID], auto_idle_pc: schemas.AutoIdlePC) -> str:
"""
Find a suitable Idle-PC value for a given IOS image. This may take a few minutes.
"""
controller = Controller.instance()
return await controller.autoidlepc(str(compute_id), auto_idle_pc.platform, auto_idle_pc.image, auto_idle_pc.ram)

@ -620,23 +620,6 @@ class Compute:
raise ControllerError(f"Connection lost to {self._id} during {method} {action}")
return res.json
async def images(self, type):
"""
Return the list of images available for this type on the compute node.
"""
res = await self.http_query("GET", f"/{type}/images", timeout=None)
images = res.json
try:
if type in ["qemu", "dynamips", "iou"]:
images = sorted(images, key=itemgetter("filename"))
else:
images = sorted(images, key=itemgetter("image"))
except OSError as e:
raise ComputeError(f"Cannot list images: {str(e)}")
return images
async def list_files(self, project):
"""
List files in the project on computes

@ -21,7 +21,7 @@ from .version import Version
# Controller schemas
from .controller.links import LinkCreate, LinkUpdate, Link
from .controller.computes import ComputeCreate, ComputeUpdate, AutoIdlePC, Compute
from .controller.computes import ComputeCreate, ComputeUpdate, ComputeVirtualBoxVM, ComputeVMwareVM, ComputeDockerImage, AutoIdlePC, Compute
from .controller.templates import TemplateCreate, TemplateUpdate, TemplateUsage, Template
from .controller.images import Image, ImageType
from .controller.appliances import ApplianceVersion, Appliance

@ -148,6 +148,31 @@ class Compute(DateTimeModelMixin, ComputeBase):
orm_mode = True
class ComputeVirtualBoxVM(BaseModel):
"""
VirtualBox VM from compute.
"""
vmname: str = Field(..., description="VirtualBox VM name")
ram: int = Field(..., description="VirtualBox VM memory")
class ComputeVMwareVM(BaseModel):
"""
VMware VM from compute.
"""
vmname: str = Field(..., description="VMware VM name")
class ComputeDockerImage(BaseModel):
"""
Docker image from compute.
"""
image: str = Field(..., description="Docker image name")
class AutoIdlePC(BaseModel):
"""
Data for auto Idle-PC request.

@ -109,7 +109,7 @@ class TestComputeRoutes:
class TestComputeFeatures:
async def test_compute_list_images(self, app: FastAPI, client: AsyncClient) -> None:
async def test_compute_list_docker_images(self, app: FastAPI, client: AsyncClient) -> None:
params = {
"protocol": "http",
@ -123,12 +123,12 @@ class TestComputeFeatures:
assert response.status_code == status.HTTP_201_CREATED
compute_id = response.json()["compute_id"]
with asyncio_patch("gns3server.controller.compute.Compute.images", return_value=[{"filename": "linux.qcow2"}, {"filename": "asav.qcow2"}]) as mock:
response = await client.get(app.url_path_for("delete_compute", compute_id=compute_id) + "/qemu/images")
assert response.json() == [{"filename": "linux.qcow2"}, {"filename": "asav.qcow2"}]
mock.assert_called_with("qemu")
with asyncio_patch("gns3server.controller.compute.Compute.forward", return_value=[{"image": "docker1"}, {"image": "docker2"}]) as mock:
response = await client.get(app.url_path_for("docker_get_images", compute_id=compute_id))
mock.assert_called_with("GET", "docker", "images")
assert response.json() == [{"image": "docker1"}, {"image": "docker2"}]
async def test_compute_list_vms(self, app: FastAPI, client: AsyncClient) -> None:
async def test_compute_list_virtualbox_vms(self, app: FastAPI, client: AsyncClient) -> None:
params = {
"protocol": "http",
@ -142,10 +142,28 @@ class TestComputeFeatures:
compute_id = response.json()["compute_id"]
with asyncio_patch("gns3server.controller.compute.Compute.forward", return_value=[]) as mock:
response = await client.get(app.url_path_for("get_compute", compute_id=compute_id) + "/virtualbox/vms")
response = await client.get(app.url_path_for("virtualbox_vms", compute_id=compute_id))
mock.assert_called_with("GET", "virtualbox", "vms")
assert response.json() == []
async def test_compute_list_vmware_vms(self, app: FastAPI, client: AsyncClient) -> None:
params = {
"protocol": "http",
"host": "localhost",
"port": 4243,
"user": "julien",
"password": "secure"
}
response = await client.post(app.url_path_for("get_computes"), json=params)
assert response.status_code == status.HTTP_201_CREATED
compute_id = response.json()["compute_id"]
with asyncio_patch("gns3server.controller.compute.Compute.forward", return_value=[]) as mock:
response = await client.get(app.url_path_for("vmware_vms", compute_id=compute_id))
mock.assert_called_with("GET", "vmware", "vms")
assert response.json() == []
async def test_compute_create_img(self, app: FastAPI, client: AsyncClient) -> None:
params = {

@ -397,29 +397,6 @@ async def test_forward_post(compute):
await compute.close()
@pytest.mark.asyncio
async def test_images(compute):
"""
Will return image on compute
"""
response = MagicMock()
response.status = 200
response.read = AsyncioMagicMock(return_value=json.dumps([{
"filename": "linux.qcow2",
"path": "linux.qcow2",
"md5sum": "d41d8cd98f00b204e9800998ecf8427e",
"filesize": 0}]).encode())
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
images = await compute.images("qemu")
mock.assert_called_with("GET", "https://example.com:84/v3/compute/qemu/images", auth=None, data=None, headers={'content-type': 'application/json'}, chunked=None, timeout=None)
await compute.close()
assert images == [
{"filename": "linux.qcow2", "path": "linux.qcow2", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "filesize": 0}
]
@pytest.mark.asyncio
async def test_list_files(project, compute):

Loading…
Cancel
Save