mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-12 19:38:57 +00:00
Optionally allow Qemu raw images
This commit is contained in:
parent
d08a052f94
commit
725942157e
@ -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}")
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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?
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user