def main_menu(session): """Show the main menu of the program""" d = session['dialog'] update_background_title(session) choices = [("Customize", "Customize image & cloud deployment options"), ("Register", "Register image to a cloud"), ("Extract", "Dump image to local file system"), ("Log", "Show current execution log"), ("Reset", "Reset everything and start over again"), ("Help", "Get help for using snf-image-creator")] default_item = "Customize" actions = { "Customize": customization_menu, "Register": kamaki_menu, "Extract": extract_image, "Log": show_log } title = "Image Creator for Synnefo (snf-image-creator v%s)" % version while 1: (code, choice) = d.menu( text="Choose one of the following or press <Exit> to exit.", width=WIDTH, choices=choices, cancel="Exit", height=13, default_item=default_item, menu_height=len(choices), title=title) if code in (d.CANCEL, d.ESC): if confirm_exit(d): break elif choice == "Reset": if confirm_reset(d): d.infobox("Resetting snf-image-creator. Please wait ...", width=SMALL_WIDTH) raise Reset elif choice == "Help": d.msgbox( "For help, check the online documentation:\n\nhttp://www" ".synnefo.org/docs/snf-image-creator/latest/", width=WIDTH, title="Help") elif choice in actions: actions[choice](session) if len(choice): default_item = choice
def main_menu(session): """Show the main menu of the program""" d = session['dialog'] update_background_title(session) choices = [("Customize", "Customize image & cloud deployment options"), ("Register", "Register image to a cloud"), ("Extract", "Dump image to local file system"), ("Log", "Show current execution log"), ("Reset", "Reset everything and start over again"), ("Help", "Get help for using snf-image-creator")] default_item = "Customize" actions = {"Customize": customization_menu, "Register": kamaki_menu, "Extract": extract_image, "Log": show_log} title = "Image Creator for Synnefo (snf-image-creator v%s)" % version while 1: (code, choice) = d.menu( text="Choose one of the following or press <Exit> to exit.", width=WIDTH, choices=choices, cancel="Exit", height=13, default_item=default_item, menu_height=len(choices), title=title) if code in (d.CANCEL, d.ESC): if confirm_exit(d): break elif choice == "Reset": if confirm_reset(d): d.infobox("Resetting snf-image-creator. Please wait ...", width=SMALL_WIDTH) raise Reset elif choice == "Help": d.msgbox("For help, check the online documentation:\n\nhttp://www" ".synnefo.org/docs/snf-image-creator/latest/", width=WIDTH, title="Help") elif choice in actions: actions[choice](session) if len(choice): default_item = choice
def sysprep(session): """Perform various system preparation tasks on the image""" d = session['dialog'] image = session['image'] # Is the image already shrinked? if image.os.shrinked: msg = "It seems you have shrinked the image. Running system " \ "preparation tasks on a shrinked image is dangerous." if d.yesno("%s\n\nDo you really want to continue?" % msg, width=SMALL_WIDTH, defaultno=1) != d.OK: return wrapper = textwrap.TextWrapper(width=WIDTH-5) syspreps = image.os.list_syspreps() if len(syspreps) == 0: d.msgbox("No system preparation task available to run!", title="System Preparation", width=SMALL_WIDTH) return while 1: choices = [] index = 0 help_title = "System Preparation Tasks" sysprep_help = "%s\n%s\n\n" % (help_title, '=' * len(help_title)) for task in syspreps: name, descr, display = image.os.sysprep_info(task) sysprep_help += "%s\n" % display sysprep_help += "%s\n" % ('-' * len(display)) sysprep_help += "%s\n\n" % wrapper.fill(" ".join(descr.split())) enabled = 1 if image.os.sysprep_enabled(task) else 0 choices.append((str(index + 1), display, enabled)) index += 1 (code, tags) = d.checklist( "Please choose which system preparation tasks you would like to " "run on the image. Press <Params> to view or modify the " "customization parameters or <Help> to see details about the " "system preparation tasks.", title="Run system preparation tasks", choices=choices, width=70, ok_label="Run", help_button=1, extra_button=1, extra_label="Params") tags = [x.strip('"') for x in tags] # Needed for OpenSUSE if code in (d.CANCEL, d.ESC): return False elif code == d.EXTRA: sysprep_params(session) elif code == d.HELP: d.scrollbox(sysprep_help, width=WIDTH) elif code == d.OK: # Enable selected syspreps and disable the rest for i in range(len(syspreps)): if str(i + 1) in tags: image.os.enable_sysprep(syspreps[i]) else: image.os.disable_sysprep(syspreps[i]) if len([s for s in image.os.list_syspreps() if image.os.sysprep_enabled(s)]) == 0: d.msgbox("No system preparation task is selected!", title="System Preparation", width=SMALL_WIDTH) continue infobox = InfoBoxOutput(d, "Image Configuration") try: image.out.append(infobox) try: # The checksum is invalid. We have mounted the image rw if 'checksum' in session: del session['checksum'] # Monitor the metadata changes during syspreps with MetadataMonitor(session, image.os.meta): try: image.os.do_sysprep() update_background_title(session) infobox.finalize() except FatalError as error: d.msgbox("System Preparation failed: %s" % error, title="System Preparation", width=SMALL_WIDTH) finally: image.out.remove(infobox) finally: infobox.cleanup() break return True
def sysprep(session): """Perform various system preparation tasks on the image""" d = session['dialog'] image = session['image'] # Is the image already shrinked? if image.os.shrinked: msg = "It seems you have shrinked the image. Running system " \ "preparation tasks on a shrinked image is dangerous." if d.yesno("%s\n\nDo you really want to continue?" % msg, width=SMALL_WIDTH, defaultno=1) != d.OK: return wrapper = textwrap.TextWrapper(width=WIDTH - 5) syspreps = image.os.list_syspreps() if len(syspreps) == 0: d.msgbox("No system preparation task available to run!", title="System Preparation", width=SMALL_WIDTH) return while 1: choices = [] index = 0 help_title = "System Preparation Tasks" sysprep_help = "%s\n%s\n\n" % (help_title, '=' * len(help_title)) for task in syspreps: _, descr, display = image.os.sysprep_info(task) sysprep_help += "%s\n" % display sysprep_help += "%s\n" % ('-' * len(display)) sysprep_help += "%s\n\n" % wrapper.fill(" ".join(descr.split())) enabled = 1 if image.os.sysprep_enabled(task) else 0 choices.append((str(index + 1), display, enabled)) index += 1 (code, tags) = d.checklist( "Please choose which system preparation tasks you would like to " "run on the image. Press <Params> to view or modify the " "customization parameters or <Help> to see details about the " "system preparation tasks.", title="Run system preparation tasks", choices=choices, width=70, ok_label="Run", help_button=1, extra_button=1, extra_label="Params") tags = [x.strip('"') for x in tags] # Needed for OpenSUSE if code in (d.CANCEL, d.ESC): return False elif code == d.EXTRA: sysprep_params(session) elif code == d.HELP: d.scrollbox(sysprep_help, width=WIDTH) elif code == d.OK: # Enable selected syspreps and disable the rest for i, _ in enumerate(syspreps): if str(i + 1) in tags: image.os.enable_sysprep(syspreps[i]) else: image.os.disable_sysprep(syspreps[i]) if len([ s for s in image.os.list_syspreps() if image.os.sysprep_enabled(s) ]) == 0: d.msgbox("No system preparation task is selected!", title="System Preparation", width=SMALL_WIDTH) continue infobox = InfoBoxOutput(d, "Image Configuration") try: image.out.append(infobox) try: # The checksum is invalid. We have mounted the image rw if 'checksum' in session: del session['checksum'] # Monitor the metadata changes during syspreps with MetadataMonitor(session, image.os.meta): try: image.os.do_sysprep() update_background_title(session) infobox.finalize() except FatalError as error: d.msgbox("System Preparation failed: %s" % error, title="System Preparation", width=SMALL_WIDTH) finally: image.out.remove(infobox) finally: infobox.cleanup() break return True
def create_image(session, answers): """Create an image using the information collected by the wizard""" image = session['image'] with_progress = OutputWthProgress() image.out.append(with_progress) try: image.out.clear() if 'virtio' in answers and image.os.sysprep_params['virtio'].value: image.os.install_virtio_drivers() # Sysprep image.os.do_sysprep() metadata = image.os.meta update_background_title(session) metadata['DESCRIPTION'] = answers['ImageDescription'] # MD5 session['checksum'] = image.md5() image.out.info() try: image.out.info("Uploading image to the cloud:") account = Kamaki.get_account(answers['Cloud']) assert account, "Cloud: %s is not valid" % answers['Cloud'] kamaki = Kamaki(account, image.out) name = "%s-%s.diskdump" % (answers['ImageName'], time.strftime("%Y%m%d%H%M")) with image.raw_device() as raw: with open(raw, 'rb') as device: remote = kamaki.upload(device, image.size, name, CONTAINER, None, "(1/3) Calculating block hashes", "(2/3) Uploading image blocks") image.out.info("(3/3) Uploading md5sum file ...", False) md5sumstr = '%s %s\n' % (session['checksum'], name) kamaki.upload(StringIO.StringIO(md5sumstr), size=len(md5sumstr), remote_path="%s.%s" % (name, 'md5sum'), container=CONTAINER, content_type="text/plain") image.out.success('done') image.out.info() image.out.info('Registering %s image with the cloud ...' % answers['RegistrationType'].lower(), False) result = kamaki.register(answers['ImageName'], remote, metadata, answers['RegistrationType'] == "Public") image.out.success('done') image.out.info("Uploading metadata file ...", False) metastring = unicode( json.dumps(result, ensure_ascii=False)).encode('utf8') kamaki.upload(StringIO.StringIO(metastring), size=len(metastring), remote_path="%s.%s" % (name, 'meta'), container=CONTAINER, content_type="application/json") image.out.success('done') if answers['RegistrationType'] == "Public": image.out.info("Sharing md5sum file ...", False) kamaki.share("%s.md5sum" % name) image.out.success('done') image.out.info("Sharing metadata file ...", False) kamaki.share("%s.meta" % name) image.out.success('done') image.out.info() except ClientError as error: raise FatalError("Storage service client: %d %s" % (error.status, error.message)) finally: image.out.remove(with_progress) text = "The %s image was successfully uploaded to the storage service " \ "and registered with the compute service of %s. Would you like " \ "to keep a local copy?" % \ (answers['RegistrationType'].lower(), answers['Cloud']) if session['dialog'].yesno(text, width=PAGE_WIDTH) == session['dialog'].OK: extract_image(session)
def create_image(d, media, out, tmp, snapshot): """Create an image out of `media'""" d.setBackgroundTitle('snf-image-creator') gauge = GaugeOutput(d, "Initialization", "Initializing...") out.append(gauge) disk = Disk(media, out, tmp) # pylint: disable=unused-argument def signal_handler(signum, frame): gauge.cleanup() disk.cleanup() signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) try: device = disk.file if not snapshot else disk.snapshot() image = disk.get_image(device) gauge.cleanup() out.remove(gauge) # Make sure the signal handler does not call gauge.cleanup again def dummy(self): # pylint: disable=unused-argument pass gauge.cleanup = type(GaugeOutput.cleanup)(dummy, gauge, GaugeOutput) session = {"dialog": d, "disk": disk, "image": image} if image.is_unsupported(): session['excluded_tasks'] = [-1] session['task_metadata'] = ["EXCLUDE_ALL_TASKS"] msg = "The system on the input media is not supported." \ "\n\nReason: %s\n\n" \ "We highly recommend not to create an image out of this, " \ "since the image won't be cleaned up and you will not be " \ "able to configure it during the deployment. Press <YES> if " \ "you still want to continue with the image creation process." \ % image._unsupported if d.yesno(msg, width=WIDTH, defaultno=1, height=12) == d.OK: main_menu(session) d.infobox("Thank you for using snf-image-creator. Bye", width=53) return 0 msg = "snf-image-creator detected a %s system on the input media. " \ "Would you like to run a wizard to assist you through the " \ "image creation process?\n\nChoose <Wizard> to run the wizard," \ " <Expert> to run snf-image-creator in expert mode or press " \ "ESC to quit the program." \ % (image.ostype.capitalize() if image.ostype == image.distro or image.distro == "unknown" else "%s (%s)" % (image.ostype.capitalize(), image.distro.capitalize())) update_background_title(session) while True: code = d.yesno(msg, width=WIDTH, height=12, yes_label="Wizard", no_label="Expert") if code == d.OK: if start_wizard(session): break elif code == d.CANCEL: main_menu(session) break if confirm_exit(d): break d.infobox("Thank you for using snf-image-creator. Bye", width=53) finally: disk.cleanup() return 0
def create_image(session, answers): """Create an image using the information collected by the wizard""" image = session['image'] with_progress = OutputWthProgress() image.out.append(with_progress) try: image.out.clear() if 'virtio' in answers and image.os.sysprep_params['virtio'].value: image.os.install_virtio_drivers() # Sysprep image.os.do_sysprep() metadata = image.os.meta update_background_title(session) metadata['DESCRIPTION'] = answers['ImageDescription'] # MD5 session['checksum'] = image.md5() image.out.info() try: image.out.info("Uploading image to the cloud:") account = Kamaki.get_account(answers['Cloud']) assert account, "Cloud: %s is not valid" % answers['Cloud'] kamaki = Kamaki(account, image.out) name = "%s-%s.diskdump" % (answers['ImageName'], time.strftime("%Y%m%d%H%M")) with image.raw_device() as raw: with open(raw, 'rb') as device: remote = kamaki.upload(device, image.size, name, CONTAINER, None, "(1/3) Calculating block hashes", "(2/3) Uploading image blocks") image.out.info("(3/3) Uploading md5sum file ...", False) md5sumstr = '%s %s\n' % (session['checksum'], name) kamaki.upload(StringIO.StringIO(md5sumstr), size=len(md5sumstr), remote_path="%s.%s" % (name, 'md5sum'), container=CONTAINER, content_type="text/plain") image.out.success('done') image.out.info() image.out.info( 'Registering %s image with the cloud ...' % answers['RegistrationType'].lower(), False) result = kamaki.register(answers['ImageName'], remote, metadata, answers['RegistrationType'] == "Public") image.out.success('done') image.out.info("Uploading metadata file ...", False) metastring = unicode(json.dumps(result, ensure_ascii=False)).encode('utf8') kamaki.upload(StringIO.StringIO(metastring), size=len(metastring), remote_path="%s.%s" % (name, 'meta'), container=CONTAINER, content_type="application/json") image.out.success('done') if answers['RegistrationType'] == "Public": image.out.info("Sharing md5sum file ...", False) kamaki.share("%s.md5sum" % name) image.out.success('done') image.out.info("Sharing metadata file ...", False) kamaki.share("%s.meta" % name) image.out.success('done') image.out.info() except ClientError as error: raise FatalError("Storage service client: %d %s" % (error.status, error.message)) finally: image.out.remove(with_progress) text = "The %s image was successfully uploaded to the storage service " \ "and registered with the compute service of %s. Would you like " \ "to keep a local copy?" % \ (answers['RegistrationType'].lower(), answers['Cloud']) if session['dialog'].yesno(text, width=PAGE_WIDTH) == session['dialog'].OK: extract_image(session)