From faa3ef8cb4b3fe7a428defeff08cb8fadeabc2f6 Mon Sep 17 00:00:00 2001 From: Jerry Seutter Date: Fri, 7 Nov 2014 20:42:08 -0700 Subject: [PATCH 1/2] Add support for Qemu devices on cloud instances --- gns3server/modules/qemu/qemu_vm.py | 62 +++++++++++++++++++++++++++++- gns3server/modules/qemu/schemas.py | 4 ++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/gns3server/modules/qemu/qemu_vm.py b/gns3server/modules/qemu/qemu_vm.py index ce341780..ffdd299d 100644 --- a/gns3server/modules/qemu/qemu_vm.py +++ b/gns3server/modules/qemu/qemu_vm.py @@ -24,6 +24,10 @@ import shutil import random import subprocess import shlex +import ntpath + +from gns3server.config import Config +from gns3dms.cloud.rackspace_ctrl import get_provider from .qemu_error import QemuError from .adapters.ethernet_adapter import EthernetAdapter @@ -86,6 +90,7 @@ class QemuVM(object): self._stdout_file = "" self._console_start_port_range = console_start_port_range self._console_end_port_range = console_end_port_range + self._cloud_path = None # QEMU settings self._qemu_path = qemu_path @@ -288,6 +293,27 @@ class QemuVM(object): log.info("QEMU VM {name} [id={id}] has been deleted (including associated files)".format(name=self._name, id=self._id)) + @property + def cloud_path(self): + """ + Returns the cloud path where images can be downloaded from. + + :returns: cloud path + """ + + return self._cloud_path + + @cloud_path.setter + def cloud_path(self, cloud_path): + """ + Sets the cloud path where images can be downloaded from. + + :param cloud_path: + :return: + """ + + self._cloud_path = cloud_path + @property def qemu_path(self): """ @@ -531,7 +557,41 @@ class QemuVM(object): if not self.is_running(): if not os.path.isfile(self._qemu_path) or not os.path.exists(self._qemu_path): - raise QemuError("QEMU binary '{}' is not accessible".format(self._qemu_path)) + found = False + paths = [os.getcwd()] + os.environ["PATH"].split(os.pathsep) + # look for the qemu binary in the current working directory and $PATH + for path in paths: + try: + if self._qemu_path in os.listdir(path) and os.access(os.path.join(path, self._qemu_path), os.X_OK): + self._qemu_path = os.path.join(path, self._qemu_path) + found = True + break + except OSError: + continue + + if not found: + raise QemuError("QEMU binary '{}' is not accessible".format(self._qemu_path)) + + if self.cloud_path is not None: + # Download from Cloud Files + if self.hda_disk_image != "": + _, filename = ntpath.split(self.hda_disk_image) + src = '{}/{}'.format(self.cloud_path, filename) + dest = os.path.join(self.working_dir, filename) + if not os.path.isfile(dest): + cloud_settings = Config.instance().cloud_settings() + provider = get_provider(cloud_settings) + provider.download_file(src, dest) + self.hda_disk_image = dest + if self.hdb_disk_image != "": + _, filename = ntpath.split(self.hdb_disk_image) + src = '{}/{}'.format(self.cloud_path, filename) + dest = os.path.join(self.working_dir, filename) + if not os.path.isfile(dest): + cloud_settings = Config.instance().cloud_settings() + provider = get_provider(cloud_settings) + provider.download_file(src, dest) + self.hdb_disk_image = dest self._command = self._build_command() try: diff --git a/gns3server/modules/qemu/schemas.py b/gns3server/modules/qemu/schemas.py index a4f340c3..885941fd 100644 --- a/gns3server/modules/qemu/schemas.py +++ b/gns3server/modules/qemu/schemas.py @@ -120,6 +120,10 @@ QEMU_UPDATE_SCHEMA = { "description": "QEMU kernel command line", "type": "string", }, + "cloud_path": { + "description": "Path to the image in the cloud object store", + "type": "string", + }, "options": { "description": "additional QEMU options", "type": "string", From 5b73786653887c754ef945eb6666eeed9d446146 Mon Sep 17 00:00:00 2001 From: Jerry Seutter Date: Mon, 10 Nov 2014 11:28:19 -0700 Subject: [PATCH 2/2] Move image path manipulation to server side --- gns3server/modules/dynamips/backends/vm.py | 13 ++++++++----- gns3server/modules/iou/__init__.py | 13 ++++++++----- gns3server/modules/qemu/qemu_vm.py | 20 ++++++++++++-------- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/gns3server/modules/dynamips/backends/vm.py b/gns3server/modules/dynamips/backends/vm.py index 0aa2491e..67c0bb73 100644 --- a/gns3server/modules/dynamips/backends/vm.py +++ b/gns3server/modules/dynamips/backends/vm.py @@ -17,6 +17,7 @@ import os import base64 +import ntpath import time from gns3server.modules import IModule from gns3dms.cloud.rackspace_ctrl import get_provider @@ -148,13 +149,15 @@ class VM(object): else: if not os.path.exists(self.images_directory): os.mkdir(self.images_directory) - if request.get("cloud_path", None): + cloud_path = request.get("cloud_path", None) + if cloud_path is not None: # Download the image from cloud files - cloud_path = request.get("cloud_path") - full_cloud_path = "/".join((cloud_path, image)) - + _, filename = ntpath.split(image) + src = '{}/{}'.format(cloud_path, filename) provider = get_provider(self._cloud_settings) - provider.download_file(full_cloud_path, updated_image_path) + log.debug("Downloading file from {} to {}...".format(src, updated_image_path)) + provider.download_file(src, updated_image_path) + log.debug("Download of {} complete.".format(src)) image = updated_image_path try: diff --git a/gns3server/modules/iou/__init__.py b/gns3server/modules/iou/__init__.py index 6243c14e..e9e1bb51 100644 --- a/gns3server/modules/iou/__init__.py +++ b/gns3server/modules/iou/__init__.py @@ -21,6 +21,7 @@ IOU server module. import os import base64 +import ntpath import stat import tempfile import socket @@ -303,13 +304,15 @@ class IOU(IModule): else: if not os.path.exists(self.images_directory): os.mkdir(self.images_directory) - if request.get("cloud_path", None): + cloud_path = request.get("cloud_path", None) + if cloud_path is not None: # Download the image from cloud files - cloud_path = request.get("cloud_path") - full_cloud_path = "/".join((cloud_path, iou_path)) - + _, filename = ntpath.split(iou_path) + src = '{}/{}'.format(cloud_path, filename) provider = get_provider(self._cloud_settings) - provider.download_file(full_cloud_path, updated_iou_path) + log.debug("Downloading file from {} to {}...".format(src, updated_iou_path)) + provider.download_file(src, updated_iou_path) + log.debug("Download of {} complete.".format(src)) # Make file executable st = os.stat(updated_iou_path) os.chmod(updated_iou_path, st.st_mode | stat.S_IEXEC) diff --git a/gns3server/modules/qemu/qemu_vm.py b/gns3server/modules/qemu/qemu_vm.py index ffdd299d..47effa6e 100644 --- a/gns3server/modules/qemu/qemu_vm.py +++ b/gns3server/modules/qemu/qemu_vm.py @@ -577,21 +577,25 @@ class QemuVM(object): if self.hda_disk_image != "": _, filename = ntpath.split(self.hda_disk_image) src = '{}/{}'.format(self.cloud_path, filename) - dest = os.path.join(self.working_dir, filename) - if not os.path.isfile(dest): + dst = os.path.join(self.working_dir, filename) + if not os.path.isfile(dst): cloud_settings = Config.instance().cloud_settings() provider = get_provider(cloud_settings) - provider.download_file(src, dest) - self.hda_disk_image = dest + log.debug("Downloading file from {} to {}...".format(src, dst)) + provider.download_file(src, dst) + log.debug("Download of {} complete.".format(src)) + self.hda_disk_image = dst if self.hdb_disk_image != "": _, filename = ntpath.split(self.hdb_disk_image) src = '{}/{}'.format(self.cloud_path, filename) - dest = os.path.join(self.working_dir, filename) - if not os.path.isfile(dest): + dst = os.path.join(self.working_dir, filename) + if not os.path.isfile(dst): cloud_settings = Config.instance().cloud_settings() provider = get_provider(cloud_settings) - provider.download_file(src, dest) - self.hdb_disk_image = dest + log.debug("Downloading file from {} to {}...".format(src, dst)) + provider.download_file(src, dst) + log.debug("Download of {} complete.".format(src)) + self.hdb_disk_image = dst self._command = self._build_command() try: