1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-11-28 11:18:11 +00:00

Optionally allow Qemu raw images

This commit is contained in:
grossmj 2022-07-22 12:39:52 +02:00
parent d08a052f94
commit 725942157e
4 changed files with 20 additions and 11 deletions

View File

@ -69,7 +69,8 @@ async def upload_image(
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
current_user: schemas.User = Depends(get_current_active_user),
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository)),
install_appliances: Optional[bool] = False
install_appliances: Optional[bool] = False,
allow_raw_image: Optional[bool] = False
) -> schemas.Image:
"""
Upload an image.
@ -90,7 +91,7 @@ async def upload_image(
raise ControllerBadRequestError(f"Image '{image_path}' already exists")
try:
image = await write_image(image_path, full_path, request.stream(), images_repo)
image = await write_image(image_path, full_path, request.stream(), images_repo, allow_raw_image=allow_raw_image)
except (OSError, InvalidImageError, ClientDisconnect) as e:
raise ControllerError(f"Could not save image '{image_path}': {e}")

View File

@ -123,7 +123,7 @@ class ApplianceManager:
async with HTTPClient.get(image_url) as response:
if response.status != 200:
raise ControllerError(f"Could not download '{image_name}' due to HTTP error code {response.status}")
await write_image(image_name, image_path, response.content.iter_any(), images_repo)
await write_image(image_name, image_path, response.content.iter_any(), images_repo, allow_raw_image=True)
except (OSError, InvalidImageError) as e:
raise ControllerError(f"Could not save {image_type} image '{image_path}': {e}")
except ClientError as e:
@ -162,7 +162,7 @@ class ApplianceManager:
cache_to_md5file=False
) == image_checksum:
async with aiofiles.open(image_path, "rb") as f:
await write_image(appliance_file, image_path, f, images_repo)
await write_image(appliance_file, image_path, f, images_repo, allow_raw_image=True)
else:
# download the image if there is a direct download URL
direct_download_url = image.get("direct_download_url")

View File

@ -91,8 +91,10 @@ async def get_computes(app: FastAPI) -> List[dict]:
def image_filter(change: Change, path: str) -> bool:
if change == Change.added and os.path.isfile(path):
if path.endswith(".tmp") or path.endswith(".md5sum") or path.startswith(".") or \
"/lib/" in path or "/lib64/" in path:
if path.endswith(".tmp") or path.endswith(".md5sum") or path.startswith("."):
return False
if "/lib/" in path or "/lib64/" in path:
# ignore custom IOU libraries
return False
header_magic_len = 7
with open(path, "rb") as f:
@ -101,10 +103,10 @@ def image_filter(change: Change, path: str) -> bool:
try:
check_valid_image_header(image_header)
except InvalidImageError as e:
log.debug(f"New image '{path}' added: {e}")
log.debug(f"New image '{path}': {e}")
return False
else:
log.debug(f"New image '{path}' added: size is too small to be valid")
log.debug(f"New image '{path}': size is too small to be valid")
return False
return True
# FIXME: should we support image deletion?

View File

@ -144,6 +144,9 @@ async def discover_images(image_type: str, skip_image_paths: list = None) -> Lis
path = os.path.join(root, filename)
if not os.path.isfile(path) or skip_image_paths and path in skip_image_paths or path in files:
continue
if "/lib/" in path or "/lib64/" in path:
# ignore custom IOU libraries
continue
files.add(path)
try:
@ -285,7 +288,7 @@ class InvalidImageError(Exception):
return self._message
def check_valid_image_header(data: bytes) -> str:
def check_valid_image_header(data: bytes, allow_raw_image: bool = False) -> str:
if data[:7] == b'\x7fELF\x01\x02\x01':
# for IOS images: file must start with the ELF magic number, be 32-bit, big endian and have an ELF version of 1
@ -298,6 +301,8 @@ def check_valid_image_header(data: bytes) -> str:
# for Qemy images: file must be QCOW2 or VMDK
return "qemu"
else:
if allow_raw_image is True:
return "qemu"
raise InvalidImageError("Could not detect image type, please make sure it is a valid image")
@ -306,7 +311,8 @@ async def write_image(
image_path: str,
stream: AsyncGenerator[bytes, None],
images_repo: ImagesRepository,
check_image_header=True
check_image_header=True,
allow_raw_image=False
) -> models.Image:
image_dir, image_name = os.path.split(image_filename)
@ -322,7 +328,7 @@ async def write_image(
async for chunk in stream:
if check_image_header and len(chunk) >= header_magic_len:
check_image_header = False
image_type = check_valid_image_header(chunk)
image_type = check_valid_image_header(chunk, allow_raw_image)
await f.write(chunk)
checksum.update(chunk)