diff --git a/image_creator/dialog_menu.py b/image_creator/dialog_menu.py index 028e6a854fcee7c652f0cc3bcd04eb4e0f52299d..831e583f9104159252ecbfde633d57752333539a 100644 --- a/image_creator/dialog_menu.py +++ b/image_creator/dialog_menu.py @@ -33,7 +33,7 @@ from image_creator.kamaki_wrapper import Kamaki, ClientError from image_creator.help import get_help_file from image_creator.dialog_util import SMALL_WIDTH, WIDTH, \ update_background_title, confirm_reset, confirm_exit, Reset, \ - extract_image, add_cloud, edit_cloud, select_file + extract_image, add_cloud, edit_cloud, virtio_versions, update_sysprep_param CONFIGURATION_TASKS = [ ("Partition table manipulation", ["FixPartitionTable"], @@ -641,45 +641,6 @@ def exclude_tasks(session): return True -def update_sysprep_param(session, name, title=None): - """Modify the value of a sysprep parameter""" - d = session['dialog'] - image = session['image'] - - param = image.os.sysprep_params[name] - - while 1: - if param.type in ("file", "dir"): - if not title: - title = "Please select a %s to use for the `%s' parameter" % \ - ('file' if param.type == 'file' else 'directory', name) - ftype = "br" if param.type == 'file' else 'd' - - value = select_file(d, ftype=ftype, title=title) - if value is None: - return False - else: - if not title: - title = "Please provide a new value for configuration " \ - "parameter: `%s'" % name - (code, answer) = d.inputbox( - title, width=WIDTH, init=str(param.value)) - - if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): - return False - - value = answer.strip() - - if param.set_value(value) is False: - d.msgbox("Unable to update the value. Reason: %s" % param.error, - width=WIDTH) - param.error = None - continue - break - - return True - - def sysprep_params(session): """Collect the needed sysprep parameters""" d = session['dialog'] @@ -740,11 +701,7 @@ def virtio(session): default_item = image.os.virtio_state.keys()[0] while 1: choices = [] - for name, infs in image.os.virtio_state.items(): - driver_ver = [drv['DriverVer'].split(',', 1) if 'DriverVer' in drv - else [] for drv in infs.values()] - vers = [v[1] if len(v) > 1 else " " for v in driver_ver] - details = "<not installed>" if len(infs) == 0 else ", ".join(vers) + for name, details in virtio_versions(image.os.virtio_state).items(): choices.append((name, details)) (code, choice) = d.menu( diff --git a/image_creator/dialog_util.py b/image_creator/dialog_util.py index 6e4c95c91fa257f12d0527fa58c9a9c473131150..faef57612b0498199f0ad410ae574fa0d6a5744c 100644 --- a/image_creator/dialog_util.py +++ b/image_creator/dialog_util.py @@ -336,4 +336,56 @@ def edit_cloud(session, name): return True + +def virtio_versions(virtio_state): + """Returns the versions of the drivers defined by the virtio state""" + + ret = {} + for name, infs in virtio_state.items(): + driver_ver = [drv['DriverVer'].split(',', 1) if 'DriverVer' in drv + else [] for drv in infs.values()] + vers = [v[1] if len(v) > 1 else " " for v in driver_ver] + ret[name] = "<not found>" if len(infs) == 0 else ", ".join(vers) + + return ret + + +def update_sysprep_param(session, name, title=None): + """Modify the value of a sysprep parameter""" + d = session['dialog'] + image = session['image'] + + param = image.os.sysprep_params[name] + + while 1: + if param.type in ("file", "dir"): + if not title: + title = "Please select a %s to use for the `%s' parameter" % \ + ('file' if param.type == 'file' else 'directory', name) + ftype = "br" if param.type == 'file' else 'd' + + value = select_file(d, ftype=ftype, title=title) + if value is None: + return False + else: + if not title: + title = "Please provide a new value for configuration " \ + "parameter: `%s'" % name + (code, answer) = d.inputbox( + title, width=WIDTH, init=str(param.value)) + + if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): + return False + + value = answer.strip() + + if param.set_value(value) is False: + d.msgbox("Unable to update the value. Reason: %s" % param.error, + width=WIDTH) + param.error = None + continue + break + + return True + # vim: set sta sts=4 shiftwidth=4 sw=4 et ai : diff --git a/image_creator/dialog_wizard.py b/image_creator/dialog_wizard.py index bdcc41746f7888097d878646739be9df30bd34d7..470eb76fc22b6fe4d36012d972523833664e784e 100644 --- a/image_creator/dialog_wizard.py +++ b/image_creator/dialog_wizard.py @@ -27,11 +27,10 @@ from image_creator.kamaki_wrapper import Kamaki, ClientError from image_creator.util import MD5, FatalError from image_creator.output.cli import OutputWthProgress from image_creator.dialog_util import extract_image, update_background_title, \ - add_cloud, edit_cloud + add_cloud, edit_cloud, virtio_versions, update_sysprep_param PAGE_WIDTH = 70 -PAGE_HEIGHT = 10 -SYSPREP_PARAM_MAXLEN = 20 +PAGE_HEIGHT = 12 class WizardExit(Exception): @@ -128,6 +127,37 @@ class WizardPage(object): raise NotImplementedError +class WizardInfoPage(WizardPage): + """Represents a Wizard Page that just displays some user-defined + information. + """ + def __init__(self, name, display_name, text, body, **kargs): + super(WizardInfoPage, self).__init__(name, display_name, text, **kargs) + self.body = body + + def run(self, session, title): + d = session['dialog'] + w = session['wizard'] + + extra_button = 1 if self.extra else 0 + text = "%s\n\n%s" % (self.text, self.body()) + + ret = d.yesno(text, width=PAGE_WIDTH, ok_label="Next", + cancel="Back", extra_button=extra_button, title=title, + extra_label=self.extra_label, height=PAGE_HEIGHT) + + if ret in (d.DIALOG_CANCEL, d.DIALOG_ESC): + return self.PREV + elif ret == d.DIALOG_EXTRA: + self.extra() + raise WizardReloadPage + + # DIALOG_OK + w[self.name] = self.validate(None) + self.info = "%s: %s" % (self.display_name, self.display(w[self.name])) + return self.NEXT + + class WizardPageWthChoices(WizardPage): """Represents a Wizard Page that allows the user to select something from a list of choices. @@ -316,6 +346,53 @@ def start_wizard(session): title="Image Description", default=session['metadata']['DESCRIPTION'] if 'DESCRIPTION' in session['metadata'] else '') + # Create VirtIO Installation Page + def display_installed_drivers(): + """Returnes the installed virtio drivers""" + versions = virtio_versions(image.os.virtio_state) + + ret = "Installed Block Device Driver: %(netkvm)s\n" \ + "Installed Network Device Driver: %(viostor)s\n" % versions + + virtio = image.os.sysprep_params['virtio'].value + if virtio: + ret += "\nNew Block Device Driver: %(netkvm)s\n" \ + "New Network Device Driver: %(viostor)s\n" % \ + virtio_versions(image.os.compute_virtio_state(virtio)) + return ret + + def validate_virtio(_): + netkvm = len(image.os.virtio_state['netkvm']) != 0 + viostor = len(image.os.virtio_state['viostor']) != 0 + drv_dir = image.os.sysprep_params['virtio'].value + + if netkvm is False or viostor is False: + new = image.os.compute_virtio_state(drv_dir) if drv_dir else None + new_viostor = len(new['viostor']) != 0 if new else False + new_netkvm = len(new['netkvm']) != 0 if new else False + + d = session['dialog'] + title = "VirtIO driver missing" + msg = "Image creation cannot proceed unless a VirtIO %s driver " \ + "is installed on the media!" + if not (viostor or new_viostor): + d.msgbox(msg % "Block Device", width=PAGE_WIDTH, + height=PAGE_HEIGHT, title=title) + raise WizardReloadPage + if not(netkvm or new_netkvm): + d.msgbox(msg % "Network Device", width=PAGE_WIDTH, + height=PAGE_HEIGHT, title=title) + raise WizardReloadPage + + return drv_dir + + virtio = WizardInfoPage( + "virtio", "VirtIO Drivers Path", + "Press <New> to install new VirtIO drivers.", + display_installed_drivers, title="VirtIO Drivers", extra_label='New', + extra=lambda: update_sysprep_param(session, 'virtio'), + validate=validate_virtio) + # Create Image Registration Wizard Page def registration_choices(): return [("Private", "Image is accessible only by this user"), @@ -326,14 +403,16 @@ def start_wizard(session): "Please provide a registration type:", registration_choices, title="Registration Type", default="Private") - w = Wizard(session) + wizard = Wizard(session) - w.add_page(cloud) - w.add_page(name) - w.add_page(descr) - w.add_page(registration) + wizard.add_page(cloud) + wizard.add_page(name) + wizard.add_page(descr) + if hasattr(image.os, 'install_virtio_drivers'): + wizard.add_page(virtio) + wizard.add_page(registration) - if w.run(): + if wizard.run(): create_image(session) else: return False @@ -353,6 +432,9 @@ def create_image(session): try: out.clear() + if 'virtio' in wizard and image.os.sysprep_params['virtio'].value: + image.os.install_virtio_drivers() + # Sysprep image.os.do_sysprep() metadata = image.os.meta diff --git a/image_creator/os_type/windows/__init__.py b/image_creator/os_type/windows/__init__.py index 8796eadd01a079034b887a8c0c08a5d265ec56b6..8767cecf4525d07e403b5f40a98bd36f5d33ee12 100644 --- a/image_creator/os_type/windows/__init__.py +++ b/image_creator/os_type/windows/__init__.py @@ -274,7 +274,7 @@ class Windows(OSBase): with self.mount(readonly=True, silent=True): self.out.output("Checking media state ...", False) self.sysprepped = self.registry.get_setup_state() > 0 - self.virtio_state = self._virtio_state() + self.virtio_state = self.compute_virtio_state() arch = self.image.g.inspect_get_arch(self.root) if arch == 'x86_64': arch = 'amd64' @@ -677,7 +677,7 @@ class Windows(OSBase): raise FatalError("Connection to the Windows VM failed after %d retries" % retries) - def _virtio_state(self, directory=None): + def compute_virtio_state(self, directory=None): """Returns information about the VirtIO drivers found either in a directory or the media itself if the directory is None. """ @@ -718,7 +718,7 @@ class Windows(OSBase): """Examines a directory for VirtIO drivers and returns only the drivers that are suitable for this media. """ - collection = self._virtio_state(dirname) + collection = self.compute_virtio_state(dirname) files = set([f.lower() for f in os.listdir(dirname) if os.path.isfile(dirname + os.sep + f)]) @@ -906,7 +906,7 @@ class Windows(OSBase): self.vm.stop(shutdown_timeout if booted else 1, fatal=False) with self.mount(readonly=True, silent=True): - self.virtio_state = self._virtio_state() + self.virtio_state = self.compute_virtio_state() viostor_service_found = self.registry.check_viostor_service() if not (len(self.virtio_state['viostor']) and viostor_service_found):