diff --git a/gns3server/api/routes/controller/images.py b/gns3server/api/routes/controller/images.py index 739d7e19..84a6f00e 100644 --- a/gns3server/api/routes/controller/images.py +++ b/gns3server/api/routes/controller/images.py @@ -56,8 +56,8 @@ async def get_images( @router.post("/upload/{image_name}", response_model=schemas.Image, status_code=status.HTTP_201_CREATED) async def upload_image( image_name: str, - image_type: schemas.ImageType, request: Request, + image_type: schemas.ImageType = schemas.ImageType.qemu, images_repo: ImagesRepository = Depends(get_repository(ImagesRepository)), ) -> schemas.Image: """ @@ -78,6 +78,11 @@ async def upload_image( except (OSError, InvalidImageError) as e: raise ControllerError(f"Could not save {image_type} image '{image_name}': {e}") + # TODO: automatically create template based on image checksum + #from gns3server.controller import Controller + #controller = Controller.instance() + #controller.appliance_manager.find_appliance_with_image(image.checksum) + return image diff --git a/gns3server/controller/appliance.py b/gns3server/controller/appliance.py index 7913f0ab..702e3ecf 100644 --- a/gns3server/controller/appliance.py +++ b/gns3server/controller/appliance.py @@ -56,6 +56,14 @@ class Appliance: def name(self): return self._data.get("name") + @property + def images(self): + return self._data.get("images") + + @property + def versions(self): + return self._data.get("versions") + @symbol.setter def symbol(self, new_symbol): self._data["symbol"] = new_symbol diff --git a/gns3server/controller/appliance_manager.py b/gns3server/controller/appliance_manager.py index 375c778a..fb2645c8 100644 --- a/gns3server/controller/appliance_manager.py +++ b/gns3server/controller/appliance_manager.py @@ -77,6 +77,20 @@ class ApplianceManager: os.makedirs(appliances_path, exist_ok=True) return appliances_path + #TODO: finish + def find_appliance_with_image(self, image_checksum): + + for appliance in self._appliances.values(): + if appliance.images: + for image in appliance.images: + if image["md5sum"] == image_checksum: + print(f"APPLIANCE FOUND {appliance.name}") + version = image["version"] + print(f"IMAGE VERSION {version}") + if image.versions: + for version in image.versions: + pass + def load_appliances(self, symbol_theme="Classic"): """ Loads appliance files from disk. diff --git a/gns3server/db/models/images.py b/gns3server/db/models/images.py index 3565d4c5..ed41564d 100644 --- a/gns3server/db/models/images.py +++ b/gns3server/db/models/images.py @@ -15,7 +15,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from sqlalchemy import Column, String, Integer +from sqlalchemy import Column, String, Integer, BigInteger from sqlalchemy.orm import relationship from .base import BaseTable @@ -28,6 +28,7 @@ class Image(BaseTable): id = Column(Integer, primary_key=True, autoincrement=True) filename = Column(String, unique=True, index=True) image_type = Column(String) + image_size = Column(BigInteger) path = Column(String) checksum = Column(String) checksum_algorithm = Column(String) diff --git a/gns3server/db/repositories/images.py b/gns3server/db/repositories/images.py index d9ef8d91..1d2f802e 100644 --- a/gns3server/db/repositories/images.py +++ b/gns3server/db/repositories/images.py @@ -57,12 +57,13 @@ class ImagesRepository(BaseRepository): result = await self._db_session.execute(query) return result.scalars().first() - async def add_image(self, image_name, image_type, path, checksum, checksum_algorithm) -> models.Image: + async def add_image(self, image_name, image_type, image_size, path, checksum, checksum_algorithm) -> models.Image: db_image = models.Image( id=None, filename=image_name, image_type=image_type, + image_size=image_size, path=path, checksum=checksum, checksum_algorithm=checksum_algorithm diff --git a/gns3server/schemas/controller/images.py b/gns3server/schemas/controller/images.py index 992e6742..bee6621e 100644 --- a/gns3server/schemas/controller/images.py +++ b/gns3server/schemas/controller/images.py @@ -34,6 +34,7 @@ class ImageBase(BaseModel): filename: str = Field(..., description="Image name") image_type: ImageType = Field(..., description="Image type") + image_size: int = Field(..., description="Image size in bytes") checksum: str = Field(..., description="Checksum value") checksum_algorithm: str = Field(..., description="Checksum algorithm") diff --git a/gns3server/utils/images.py b/gns3server/utils/images.py index 3843d6f6..c8e96ca8 100644 --- a/gns3server/utils/images.py +++ b/gns3server/utils/images.py @@ -236,9 +236,9 @@ def check_valid_image_header(data: bytes, image_type: str, header_magic_len: int # (normal IOS images are big endian!) if data[:header_magic_len] != b'\x7fELF\x01\x01\x01' and data[:7] != b'\x7fELF\x02\x01\x01': raise InvalidImageError("Invalid IOU file detected") - # elif image_type == "qemu": - # if data[:expected_header_magic_len] != b'QFI\xfb': - # raise InvalidImageError("Invalid Qemu file detected (must be raw or qcow2)") + elif image_type == "qemu": + if data[:header_magic_len] != b'QFI\xfb': + raise InvalidImageError("Invalid Qemu file detected (must be qcow2 format)") async def write_image( @@ -267,8 +267,8 @@ async def write_image( await f.write(chunk) checksum.update(chunk) - file_size = os.path.getsize(tmp_path) - if not file_size or file_size < header_magic_len: + image_size = os.path.getsize(tmp_path) + if not image_size or image_size < header_magic_len: raise InvalidImageError("The image content is empty or too small to be valid") checksum = checksum.hexdigest() @@ -280,4 +280,4 @@ async def write_image( raise os.chmod(tmp_path, stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC) shutil.move(tmp_path, path) - return await images_repo.add_image(image_name, image_type, path, checksum, checksum_algorithm="md5") + return await images_repo.add_image(image_name, image_type, image_size, path, checksum, checksum_algorithm="md5")