Appliance management refactoring:

* Install an appliance based on selected version
* Each template have unique name and version
* Allow to download an appliance file
This commit is contained in:
grossmj committed 2021-10-18 18:04:30 +10:30
1 parent 8a643cf4a4
commit 04934691df
11 files changed
+326 -76

No files matched your search

+43 -5
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2020 GNS3 Technologies Inc.
# 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
@@ -15,7 +15,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import pytest
import shutil
from fastapi import FastAPI, status
from httpx import AsyncClient
@@ -23,8 +25,44 @@ from httpx import AsyncClient
pytestmark = pytest.mark.asyncio
async def test_appliances_list(app: FastAPI, client: AsyncClient) -> None:
class TestApplianceRoutes:
response = await client.get(app.url_path_for("get_appliances"))
assert response.status_code == status.HTTP_200_OK
assert len(response.json()) > 0
async def test_appliances_list(self, app: FastAPI, client: AsyncClient) -> None:
response = await client.get(app.url_path_for("get_appliances"))
assert response.status_code == status.HTTP_200_OK
assert len(response.json()) > 0
async def test_appliance_download(self, app: FastAPI, client: AsyncClient) -> None:
appliance_id = "3bf492b6-5717-4257-9bfd-b34617c6f133" # Cisco IOSv appliance
response = await client.get(app.url_path_for("download_appliance", appliance_id=appliance_id))
assert response.status_code == status.HTTP_200_OK
assert response.json()["appliance_id"] == appliance_id
async def test_docker_appliance_install(self, app: FastAPI, client: AsyncClient) -> None:
appliance_id = "fc520ae2-a4e5-48c3-9a13-516bb2e94668" # Alpine Linux appliance
response = await client.post(app.url_path_for("install_appliance", appliance_id=appliance_id))
assert response.status_code == status.HTTP_204_NO_CONTENT
async def test_docker_appliance_install_with_version(self, app: FastAPI, client: AsyncClient) -> None:
appliance_id = "fc520ae2-a4e5-48c3-9a13-516bb2e94668" # Alpine Linux appliance
params = {"version": "123"}
response = await client.post(app.url_path_for("install_appliance", appliance_id=appliance_id), params=params)
assert response.status_code == status.HTTP_400_BAD_REQUEST
async def test_qemu_appliance_install_with_version(self, app: FastAPI, client: AsyncClient, images_dir: str) -> None:
shutil.copy("tests/resources/empty8G.qcow2", os.path.join(images_dir, "QEMU", "empty8G.qcow2"))
appliance_id = "1cfdf900-7c30-4cb7-8f03-3f61d2581633" # Empty VM appliance
params = {"version": "8G"}
response = await client.post(app.url_path_for("install_appliance", appliance_id=appliance_id), params=params)
assert response.status_code == status.HTTP_204_NO_CONTENT
async def test_qemu_appliance_install_without_version(self, app: FastAPI, client: AsyncClient, images_dir: str) -> None:
appliance_id = "1cfdf900-7c30-4cb7-8f03-3f61d2581633" # Empty VM appliance
response = await client.post(app.url_path_for("install_appliance", appliance_id=appliance_id))
assert response.status_code == status.HTTP_400_BAD_REQUEST
@@ -23,7 +23,9 @@ from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import FastAPI, status
from httpx import AsyncClient
from gns3server.controller import Controller
from gns3server.db.repositories.images import ImagesRepository
from gns3server.db.repositories.templates import TemplatesRepository
pytestmark = pytest.mark.asyncio
@@ -256,3 +258,27 @@ class TestImageRoutes:
images_repo = ImagesRepository(db_session)
images_in_db = await images_repo.get_images()
assert len(images_in_db) == 0
async def test_image_upload_create_appliance(
self, app: FastAPI,
client: AsyncClient,
db_session: AsyncSession,
controller: Controller
) -> None:
controller.appliance_manager.load_appliances() # make sure appliances are loaded
image_path = "tests/resources/empty30G.qcow2"
image_name = os.path.basename(image_path)
with open(image_path, "rb") as f:
image_data = f.read()
response = await client.post(
app.url_path_for("upload_image", image_path=image_name),
params={"image_type": "qemu"},
content=image_data)
assert response.status_code == status.HTTP_201_CREATED
templates_repo = TemplatesRepository(db_session)
templates = await templates_repo.get_templates()
assert len(templates) == 1
assert templates[0].name == "Empty VM"
assert templates[0].version == "30G"
+24 -4
View File
@@ -62,6 +62,7 @@ class TestTemplateRoutes:
template_id = str(uuid.uuid4())
params = {"template_id": template_id,
"name": "VPCS_TEST",
"version": "1.0",
"compute_id": "local",
"template_type": "vpcs"}
@@ -72,9 +73,25 @@ class TestTemplateRoutes:
assert response.status_code == status.HTTP_200_OK
assert response.json()["template_id"] == template_id
async def test_template_create_same_name_and_version(
self,
app: FastAPI,
client: AsyncClient,
controller: Controller
) -> None:
params = {"name": "VPCS_TEST",
"version": "1.0",
"compute_id": "local",
"template_type": "vpcs"}
response = await client.post(app.url_path_for("create_template"), json=params)
assert response.status_code == status.HTTP_409_CONFLICT
async def test_template_create_wrong_type(self, app: FastAPI, client: AsyncClient, controller: Controller) -> None:
params = {"name": "VPCS_TEST",
"version": "2.0",
"compute_id": "local",
"template_type": "invalid_template_type"}
@@ -86,6 +103,7 @@ class TestTemplateRoutes:
template_id = str(uuid.uuid4())
params = {"template_id": template_id,
"name": "VPCS_TEST",
"version": "3.0",
"compute_id": "local",
"template_type": "vpcs"}
@@ -107,6 +125,7 @@ class TestTemplateRoutes:
template_id = str(uuid.uuid4())
params = {"template_id": template_id,
"name": "VPCS_TEST",
"version": "4.0",
"compute_id": "local",
"template_type": "vpcs"}
@@ -426,7 +445,7 @@ class TestDynamipsTemplate:
async def test_c3600_dynamips_template_create_wrong_chassis(self, app: FastAPI, client: AsyncClient) -> None:
params = {"name": "Cisco c3600 template",
params = {"name": "Cisco c3600 template with wrong chassis",
"platform": "c3600",
"chassis": "3650",
"compute_id": "local",
@@ -530,7 +549,7 @@ class TestDynamipsTemplate:
async def test_c2600_dynamips_template_create_wrong_chassis(self, app: FastAPI, client: AsyncClient) -> None:
params = {"name": "Cisco c2600 template",
params = {"name": "Cisco c2600 template with wrong chassis",
"platform": "c2600",
"chassis": "2660XM",
"compute_id": "local",
@@ -589,7 +608,7 @@ class TestDynamipsTemplate:
async def test_c1700_dynamips_template_create_wrong_chassis(self, app: FastAPI, client: AsyncClient) -> None:
params = {"name": "Cisco c1700 template",
params = {"name": "Cisco c1700 template with wrong chassis",
"platform": "c1700",
"chassis": "1770",
"compute_id": "local",
@@ -1200,6 +1219,7 @@ class TestImageAssociationWithTemplate:
) -> None:
params = {"name": "Qemu template",
"version": "1.0",
"compute_id": "local",
"platform": "i386",
"hda_disk_image": "subdir/image.qcow2",
@@ -1224,7 +1244,7 @@ class TestImageAssociationWithTemplate:
async def test_template_create_with_non_existing_image(self, app: FastAPI, client: AsyncClient) -> None:
params = {"name": "Qemu template",
params = {"name": "Qemu template with non existing image",
"compute_id": "local",
"platform": "i386",
"hda_disk_image": "unkown_image.qcow2",