diff --git a/gns3server/api/routes/controller/computes.py b/gns3server/api/routes/controller/computes.py index 67652443..963ff099 100644 --- a/gns3server/api/routes/controller/computes.py +++ b/gns3server/api/routes/controller/computes.py @@ -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) diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index d8caa17c..29201759 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -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 diff --git a/gns3server/schemas/__init__.py b/gns3server/schemas/__init__.py index 77a5c9c3..d9ff9015 100644 --- a/gns3server/schemas/__init__.py +++ b/gns3server/schemas/__init__.py @@ -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 diff --git a/gns3server/schemas/controller/computes.py b/gns3server/schemas/controller/computes.py index 1c035dc7..8dc6d722 100644 --- a/gns3server/schemas/controller/computes.py +++ b/gns3server/schemas/controller/computes.py @@ -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. diff --git a/tests/api/routes/controller/test_computes.py b/tests/api/routes/controller/test_computes.py index 70134771..bd775d90 100644 --- a/tests/api/routes/controller/test_computes.py +++ b/tests/api/routes/controller/test_computes.py @@ -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 = { diff --git a/tests/controller/test_compute.py b/tests/controller/test_compute.py index 68a8670b..26939b3c 100644 --- a/tests/controller/test_compute.py +++ b/tests/controller/test_compute.py @@ -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):