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

Merge pull request #1462 from GNS3/use-files-as-disk-images

Allow virtual machines to use files in project directory as disk images.
This commit is contained in:
Jeremy Grossmann 2018-11-19 16:41:36 +07:00 committed by GitHub
commit ca6a0708a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 31 deletions

View File

@ -469,12 +469,14 @@ class BaseManager:
except PermissionError:
raise aiohttp.web.HTTPForbidden()
def get_abs_image_path(self, path):
def get_abs_image_path(self, path, extra_dir=None):
"""
Get the absolute path of an image
:param path: file path
:return: file path
:param extra_dir: an additional directory to be added to the search path
:returns: file path
"""
if not path:
@ -483,6 +485,9 @@ class BaseManager:
server_config = self.config.get_section_config("Server")
img_directory = self.get_images_directory()
valid_directory_prefices = images_directories(self._NODE_TYPE)
if extra_dir:
valid_directory_prefices.append(extra_dir)
# Windows path should not be send to a unix server
if not sys.platform.startswith("win"):
@ -490,7 +495,7 @@ class BaseManager:
raise NodeError("{} is not allowed on this remote server. Please use only a filename in {}.".format(path, img_directory))
if not os.path.isabs(path):
for directory in images_directories(self._NODE_TYPE):
for directory in valid_directory_prefices:
path = self._recursive_search_file_in_directory(directory, orig_path)
if path:
return force_unix_path(path)
@ -502,15 +507,16 @@ class BaseManager:
return path
raise ImageMissingError(orig_path)
# For non local server we disallow using absolute path outside image directory
# For local server we allow using absolute path outside image directory
if server_config.getboolean("local", False) is True:
path = force_unix_path(path)
if os.path.exists(path):
return path
raise ImageMissingError(orig_path)
# Check to see if path is an absolute path to a valid directory
path = force_unix_path(path)
for directory in images_directories(self._NODE_TYPE):
for directory in valid_directory_prefices:
if os.path.commonprefix([directory, path]) == directory:
if os.path.exists(path):
return path
@ -534,23 +540,29 @@ class BaseManager:
return path
return None
def get_relative_image_path(self, path):
def get_relative_image_path(self, path, extra_dir=None):
"""
Get a path relative to images directory path
or an abspath if the path is not located inside
image directory
:param path: file path
:return: file path
:param extra_dir: an additional directory to be added to the search path
:returns: file path
"""
if not path:
return ""
path = force_unix_path(self.get_abs_image_path(path))
path = force_unix_path(self.get_abs_image_path(path, extra_dir))
img_directory = self.get_images_directory()
for directory in images_directories(self._NODE_TYPE):
valid_directory_prefices = images_directories(self._NODE_TYPE)
if extra_dir:
valid_directory_prefices.append(extra_dir)
for directory in valid_directory_prefices:
if os.path.commonprefix([directory, path]) == directory:
relpath = os.path.relpath(path, directory)
# We don't allow to recurse search from the top image directory just for image type directory (compatibility with old releases)

View File

@ -169,8 +169,7 @@ class Router(BaseNode):
"mac_addr": self._mac_addr,
"system_id": self._system_id}
# return the relative path if the IOS image is in the images_path directory
router_info["image"] = self.manager.get_relative_image_path(self._image)
router_info["image"] = self.manager.get_relative_image_path(self._image, self.project.path)
# add the slots
slot_number = 0
@ -484,7 +483,7 @@ class Router(BaseNode):
:param image: path to IOS image file
"""
image = self.manager.get_abs_image_path(image)
image = self.manager.get_abs_image_path(image, self.project.path)
await self._hypervisor.send('vm set_ios "{name}" "{image}"'.format(name=self._name, image=image))

View File

@ -75,7 +75,7 @@ class IOUVM(BaseNode):
self._iou_stdout_file = ""
self._started = False
self._nvram_watcher = None
self._path = self.manager.get_abs_image_path(path)
self._path = self.manager.get_abs_image_path(path, project.path)
self._license_check = True
# IOU settings
@ -137,7 +137,7 @@ class IOUVM(BaseNode):
:param path: path to the IOU image executable
"""
self._path = self.manager.get_abs_image_path(path)
self._path = self.manager.get_abs_image_path(path, self.project.path)
log.info('IOU "{name}" [{id}]: IOU image updated to "{path}"'.format(name=self._name, id=self._id, path=self._path))
@property
@ -232,8 +232,7 @@ class IOUVM(BaseNode):
"command_line": self.command_line,
"application_id": self.application_id}
# return the relative path if the IOU image is in the images_path directory
iou_vm_info["path"] = self.manager.get_relative_image_path(self.path)
iou_vm_info["path"] = self.manager.get_relative_image_path(self.path, self.project.path)
return iou_vm_info
@property

View File

@ -212,7 +212,7 @@ class QemuVM(BaseNode):
:param value: New disk value
"""
value = self.manager.get_abs_image_path(value)
value = self.manager.get_abs_image_path(value, self.project.path)
if not self.linked_clone:
for node in self.manager.nodes:
if node != self and getattr(node, variable) == value:
@ -412,7 +412,8 @@ class QemuVM(BaseNode):
:param cdrom_image: QEMU cdrom image path
"""
self._cdrom_image = self.manager.get_abs_image_path(cdrom_image)
self._cdrom_image = self.manager.get_abs_image_path(cdrom_image, self.project.path)
log.info('QEMU VM "{name}" [{id}] has set the QEMU cdrom image path to {cdrom_image}'.format(name=self._name,
id=self._id,
cdrom_image=self._cdrom_image))
@ -434,7 +435,8 @@ class QemuVM(BaseNode):
:param bios_image: QEMU bios image path
"""
self._bios_image = self.manager.get_abs_image_path(bios_image)
self._bios_image = self.manager.get_abs_image_path(bios_image, self.project.path)
log.info('QEMU VM "{name}" [{id}] has set the QEMU bios image path to {bios_image}'.format(name=self._name,
id=self._id,
bios_image=self._bios_image))
@ -739,7 +741,7 @@ class QemuVM(BaseNode):
:param initrd: QEMU initrd path
"""
initrd = self.manager.get_abs_image_path(initrd)
initrd = self.manager.get_abs_image_path(initrd, self.project.path)
log.info('QEMU VM "{name}" [{id}] has set the QEMU initrd path to {initrd}'.format(name=self._name,
id=self._id,
@ -766,7 +768,7 @@ class QemuVM(BaseNode):
:param kernel_image: QEMU kernel image path
"""
kernel_image = self.manager.get_abs_image_path(kernel_image)
kernel_image = self.manager.get_abs_image_path(kernel_image, self.project.path)
log.info('QEMU VM "{name}" [{id}] has set the QEMU kernel image path to {kernel_image}'.format(name=self._name,
id=self._id,
kernel_image=kernel_image))
@ -1938,22 +1940,20 @@ class QemuVM(BaseNode):
answer[field] = getattr(self, field)
except AttributeError:
pass
answer["hda_disk_image"] = self.manager.get_relative_image_path(self._hda_disk_image)
answer["hda_disk_image"] = self.manager.get_relative_image_path(self._hda_disk_image, self.project.path)
answer["hda_disk_image_md5sum"] = md5sum(self._hda_disk_image)
answer["hdb_disk_image"] = self.manager.get_relative_image_path(self._hdb_disk_image)
answer["hdb_disk_image"] = self.manager.get_relative_image_path(self._hdb_disk_image, self.project.path)
answer["hdb_disk_image_md5sum"] = md5sum(self._hdb_disk_image)
answer["hdc_disk_image"] = self.manager.get_relative_image_path(self._hdc_disk_image)
answer["hdc_disk_image"] = self.manager.get_relative_image_path(self._hdc_disk_image, self.project.path)
answer["hdc_disk_image_md5sum"] = md5sum(self._hdc_disk_image)
answer["hdd_disk_image"] = self.manager.get_relative_image_path(self._hdd_disk_image)
answer["hdd_disk_image"] = self.manager.get_relative_image_path(self._hdd_disk_image, self.project.path)
answer["hdd_disk_image_md5sum"] = md5sum(self._hdd_disk_image)
answer["cdrom_image"] = self.manager.get_relative_image_path(self._cdrom_image)
answer["cdrom_image"] = self.manager.get_relative_image_path(self._cdrom_image, self.project.path)
answer["cdrom_image_md5sum"] = md5sum(self._cdrom_image)
answer["bios_image"] = self.manager.get_relative_image_path(self._bios_image)
answer["bios_image"] = self.manager.get_relative_image_path(self._bios_image, self.project.path)
answer["bios_image_md5sum"] = md5sum(self._bios_image)
answer["initrd"] = self.manager.get_relative_image_path(self._initrd)
answer["initrd"] = self.manager.get_relative_image_path(self._initrd, self.project.path)
answer["initrd_md5sum"] = md5sum(self._initrd)
answer["kernel_image"] = self.manager.get_relative_image_path(self._kernel_image)
answer["kernel_image"] = self.manager.get_relative_image_path(self._kernel_image, self.project.path)
answer["kernel_image_md5sum"] = md5sum(self._kernel_image)
return answer

View File

@ -101,6 +101,18 @@ def test_qemu_create_with_params(http_compute, project, base_params, fake_qemu_v
assert response.json["hda_disk_image_md5sum"] == "c4ca4238a0b923820dcc509a6f75849b"
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_qemu_create_with_project_file(http_compute, project, base_params, fake_qemu_vm):
response = http_compute.post("/projects/{project_id}/files/hello.img".format(project_id=project.id), body="world", raw=True)
assert response.status == 200
params = base_params
params["hda_disk_image"] = "hello.img"
response = http_compute.post("/projects/{project_id}/qemu/nodes".format(project_id=project.id), params, example=True)
assert response.status == 201
assert response.json["hda_disk_image"] == "hello.img"
assert response.json["hda_disk_image_md5sum"] == "7d793037a0760186574b0282f2f435e7"
def test_qemu_get(http_compute, project, vm):
response = http_compute.get("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
assert response.status == 200