class Controller(object): """ Orchestrates the installer """ def __init__(self, model, viewer): """ Constructs the controller rtype: nothing returns: nothing """ # create logger logging.basicConfig(filename=LIVECD_INSTALLER_LOG, level=logging.DEBUG, format=LOG_FORMATTER) self.__logger = logging.getLogger(__name__) self.__logger.setLevel(logging.DEBUG) self.__model = model self.__viewer = viewer try: # validate log directory if not os.path.isdir(POWERKVM_LOG_DIR): os.makedirs(POWERKVM_LOG_DIR) self.__scriptController = ScriptFactory() # pack event data self.__data = {'model': model} self.__logger.info("Screen while detecting network") firstScreen = viewer.getFirstScreen() firstScreen.show() # notifies EVT_PRE_INSTALL self.__scriptController.notify(EVT_PRE_INSTALL, self.__data) # create partitioner instance self.__partitioner = Partitioner(self.__logger) except PKVMError as e: self.__logger.critical("PKVMError: %s" % e.getLogCode(e.args)) self.__createLog() self.__viewer.getGeneralTopError().run(e.getCode(e.args)) self.rebootSystem(True) except Exception as e: self.__logger.critical(STR_VERSION + ": Unexpected error (INIT).") self.__logger.critical("EXCEPTION:" + str(type(e))) self.__logger.critical(str(e)) self.__logger.critical("Stacktrace:" + str(traceback.format_exc())) pkvmError = PKVMError() unexpectedCode = pkvmError.getUnexpectedCode("CONTROLLER", "INIT") self.__logger.critical("PKVMError: %s" % pkvmError.getLogCode(unexpectedCode[0])) self.__createLog() self.__viewer.getGeneralTopError().run(unexpectedCode) self.rebootSystem(True) # __init__() def loop(self): """ Handles the main application loop @rtype: nothing @returns: nothing """ try: # Check if automated or not if self.__data['model'].get('action') in ['install', 'reinstall', 'upgrade']: self.automatedInstalls() self.__logger.info('Manual mode') language = choose_language(self.__viewer) # Check entitlement self.__logger.info("Checking entitlement...") if not isEntitled(self.__data): self.__logger.critical("Hardware is not entitled, aborting installation!") raise PKVMError("CONTROLLER", "INSTALLPROGRESS", "ENTITLEMENT") # obtain disk information and previous installs diskInfoWnd = self.__viewer.getMessageWindow() diskInfoWnd.show(GETTING_DISK_INFORMATION.localize()) self.__partitioner.getDiskInfo() self.__partitioner.detectPreviousInstalls() diskInfoWnd.popWindow() licenseRet = self.license(language) while True: if not licenseRet: language = choose_language(self.__viewer) licenseRet = self.license(language) continue # start the menu rc = self.menu() if rc == "back": language = choose_language(self.__viewer) licenseRet = self.license(language) except PKVMError as e: self.__logger.critical("PKVMError: %s" % e.getLogCode(e.args)) self.__createLog() self.__viewer.getGeneralTopError().run(e.getCode(e.args)) self.rebootSystem(True) except Exception as e: self.__logger.critical(STR_VERSION + ": Unexpected error (LOOP).") self.__logger.critical("EXCEPTION:" + str(type(e))) self.__logger.critical(str(e)) self.__logger.critical("Stacktrace:" + str(traceback.format_exc())) pkvmError = PKVMError() unexpectedCode = pkvmError.getUnexpectedCode("CONTROLLER", "LOOP") self.__logger.critical("PKVMError: %s" % pkvmError.getLogCode(unexpectedCode[0])) self.__createLog() self.__viewer.getGeneralTopError().run(unexpectedCode) self.rebootSystem(True) # loop() def automatedInstalls(self): """ Handles automated installs @rtype: nothing @returns: nothing """ try: self.__logger.info("Unattended installation (auto mode - kickstart)") # Check entitlement self.__logger.info("Checking entitlement...") if not isEntitled(self.__data): self.__logger.critical("Hardware is not entitled, aborting installation!") raise PKVMError("CONTROLLER", "INSTALLPROGRESS", "ENTITLEMENT") self.__viewer.getMessageWindow().show(GETTING_DISK_INFORMATION.localize()) self.__partitioner.getDiskInfo() self.__partitioner.detectPreviousInstalls() # automated installation action selected: perform required operations if self.__data['model'].get('action') == 'install': # get given disk on kickstart disk = self.getDiskAutoInstall(self.__data['model'].get('disk')) # install system on given disk self.__logger.info("Automated install on %s" % disk) self.installProgress(disk) # automated reinstallation action selected: perform required operations elif self.__data['model'].get('action') == 'reinstall': self.__logger.info("Automated reinstall") # preinstall module can't detect a previous system installed: abort if self.__partitioner.detectedPreviousInstall() is False: self.__logger.critical('Automated install failed: no previous system found') self.__viewer.getReinstallError().run() raise PKVMError("CONTROLLER", "AUTOINSTALL", "NO_PREINSTALL") # reinstall process can continue: call correct method # important: here the disk is not important, because we already # detected it to reinstall the system self.installProgress('') # automated upgrade action selected: perform required operations elif self.__data['model'].get('action') == 'upgrade': self.__logger.info("Automated upgrade") self.upgradeProgress(False) return except PKVMError as e: raise except Exception as e: self.__logger.critical(STR_VERSION + ": Unexpected error while executing kickstart.") self.__logger.critical("EXCEPTION:" + str(type(e))) self.__logger.critical(str(e)) self.__logger.critical("Stacktrace:" + str(traceback.format_exc())) raise PKVMError("CONTROLLER", "AUTOINSTALL", "UNEXPECTED_AUTOINSTALL") # automatedInstalls() def license(self, language): """ Handles the License screen @rtype: nothing @returns: nothing """ self.__logger.info('License screen') # instantiate the license window for IBM License licenseWindow = self.__viewer.getLicenseWindow() # display the IBM license in the selected language if not licenseWindow.run(getIBMLicense(language, self.__logger), False): return False # instantiate the license window for Notices licenseWindow = self.__viewer.getLicenseWindow() # display the Non IBM License and Notices (english only) if not licenseWindow.run(getNonIBMLicenseNotices(self.__logger), True): self.__logger.info('Non IBM licenses and notices declined, rebooting') self.rebootSystem(True) self.__data['model'].insert('licenseAccepted', True) return True # license() def menu(self): """ Handles the Menu screen @rtype: nothing @returns: nothing """ self.__logger.info('Menu screen') # options to be configured on menu screen menuOptions = [] # install option menuOptions.append((INSTALL_IBM_POWERKVM.localize(), "install")) # previous KoP system installed: give more options if self.__partitioner.detectedPreviousInstall() is True: menuOptions.append((REINSTALL_IBM_POWERKVM.localize(), 'reinstall')) #menuOptions.append((UPGRADE_INSTALLED_IBM_POWERKVM.localize(), 'upgrade')) # get menu screen instance menuScreen = self.__viewer.getMenu() # configure menu options menuScreen.setMenuOptions(menuOptions) # run menu screen and get the user option rc = menuScreen.run() if rc[0] == "back": return "back" else: rc = rc[1] # user wants to install: call disk screen if rc == 'install': self.diskSelection() return # user wants to reinstall system: show a confirmation screen elif rc == 'reinstall': if self.__partitioner.detectedPreviousInstall(): installed_disk = self.__partitioner.getPreviousInstalledDisk() self.reinstallConfirmation(installed_disk) return else: # no previous installation detected, cannot reinstall self.__logger.critical('Reinstall failed: no previous system found') self.__viewer.getReinstallError().run() raise PKVMError("CONTROLLER", "REINSTALL", "NO_PREINSTALL") return # user wants to upgrade: call upgrade process elif rc == 'upgrade': self.upgradeProgress(True) return self.__logger.info('Quit to rescue mode') # menu() def getDiskAutoInstall(self, disk): """ Get and validate the disk device provided by kickstart. @type: disk:str @params: disk: path disk (can be device, disk-id or disk-label path) @rtype: str @returns: device disk path to be used by installer """ try: self.__logger.info("Getting and validating disk from kickstart.") self.__logger.debug("Disk path to be verified: %s" % disk) # get disk in case disk-label was provided disk = self.getDiskByLabel(disk) # get disk in case disk-id was provided disk = self.getDiskById(disk) # get all available disks disks = self.getAvailableDisks() # check if provided disk exists in the system. if disk.split('/')[-1] not in disks.keys(): self.__logger.critical("No disk %s found in the system." % disk) raise PKVMError("CONTROLLER", "GETDISKAUTOINSTALL", "NO_DISK") # check if the provided disk has the minimun required size. if disks[disk.split("/")[-1]][2] < 70: self.__viewer.getDiskSelectionError().showErrorDiskSize() self.__logger.critical("Invalid disk size (%s) < 70G." % disk) raise PKVMError("CONTROLLER", "GETDISKAUTOINSTALL", "DISK_SIZE") self.__logger.debug("Disk path to be used: %s" % disk) return disk except PKVMError as e: raise except Exception as e: self.__logger.critical(STR_VERSION + ": Unexpected error while getting the disk provided by kickstart.") self.__logger.critical("EXCEPTION:" + str(type(e))) self.__logger.critical(str(e)) self.__logger.critical("Stacktrace:" + str(traceback.format_exc())) raise PKVMError("CONTROLLER", "GETDISKAUTOINSTALL", "UNEXPECTED_AUTOINSTALL") # getDiskAutoInstall() def getDiskByLabel(self, disk): """ Get the disk path if disk-label was provided. @type: disk:str @params: disk: path of disk-label @rtype: str @returns: disk path to be used by installer """ try: self.__logger.info("Getting disk by LABEL if applicable...") self.__logger.debug("Disk path to be verified (LABEL): %s" % disk) diskLabel = None # verify if disk provided is disk-label if len(disk.split("=")) == 2 and disk.split("=")[0] == 'LABEL': diskLabel = "/dev/disk/by-label/%s" % disk.split("=")[1] elif disk.startswith("/dev/disk/by-label/"): diskLabel = disk retDisk = None if diskLabel: proc = Popen(['readlink', diskLabel], stdout=PIPE, stderr=PIPE) out, err = proc.communicate() if proc.returncode != 0: self.__logger.critical("Failed to get disk LABEL (%s) (exit code = %s):" % (diskLabel, proc.returncode)) self.__logger.critical("%s" % err) raise PKVMError("CONTROLLER", "GETDISKBYLABEL", "NO_DISK") retDisk = out.rstrip() else: retDisk = disk self.__logger.debug("Disk path to be used (LABEL): %s" % retDisk) return retDisk except PKVMError as e: raise except Exception as e: self.__logger.critical(STR_VERSION + ": Unexpected error while disk by label.") self.__logger.critical("EXCEPTION:" + str(type(e))) self.__logger.critical(str(e)) self.__logger.critical("Stacktrace:" + str(traceback.format_exc())) raise PKVMError("CONTROLLER", "GETDISKBYLABEL", "UNEXPECTED_GETDISKS") # getDiskByLabel() def getDiskById(self, disk): """ Get the disk path if disk-id was provided @type: disk:str @params: disk: path of disk-id @rtype: str @returns: disk path to be used by installer """ try: self.__logger.info("Getting disk by ID if applicable...") self.__logger.debug("Disk path to be verified (ID): %s" % disk) retDisk = None # verify if disk provided is disk-id if disk.startswith("/dev/disk/by-id/"): disks = self.__partitioner.getDisks() for d in disks: if d['id'] == disk: # verify if it is multipath if d['mpath_master'] is not None: retDisk = "dev/mapper/%s" % d['mpath_master'] else: retDisk = "/dev/%s" % d['name'] break else: retDisk = disk if retDisk is None: self.__logger.critical("No disk ID found in the system. Exiting...") raise PKVMError("CONTROLLER", "GETDISKBYID", "NO_DISK") else: self.__logger.debug("Disk path to be used (ID): %s" % retDisk) return retDisk except PKVMError as e: raise except Exception as e: self.__logger.critical(STR_VERSION + ": Unexpected error while disk by id.") self.__logger.critical("EXCEPTION:" + str(type(e))) self.__logger.critical(str(e)) self.__logger.critical("Stacktrace:" + str(traceback.format_exc())) raise PKVMError("CONTROLLER", "GETDISKBYID", "UNEXPECTED_GETDISKS") # getDiskById() def getAvailableDisks(self): """ Get all available disks and return as a list @rtype: list @returns: list of disks """ try: disks = dict() self.__logger.info('DiskSelection screen') detdisks = self.__partitioner.getDisks() for disk in detdisks: # skip if disk is not writable if not disk['accessible']: self.__logger.critical('It is not possible to write on %s' % disk['name']) continue id = disk['id'].split('/')[4] disk_info = [id, int(disk['size']) * int(disk['sectorSize']) / GIGABYTES] if disk['mpath_master'] is not None: # filter fibre-channel disks if len(disk['mpath_slaves']) > 0 and isSAN(disk['mpath_slaves'][0]): self.__logger.info('Installation on %s [%s] is not yet supported - FC' % (disk['mpath_master'], ', '.join(disk['mpath_slaves']))) continue disks[disk['mpath_master']] = [disk['mpath_master']] + disk_info continue # filter fibre-channel disks if isSAN(disk['name']): self.__logger.info('Installation in %s is not yet supported - FC' % disk['name']) continue disks[disk['name']] = [disk['name']] + disk_info return disks except PKVMError as e: raise except Exception as e: self.__logger.critical(STR_VERSION + ": Unexpected error while verifying disks.") self.__logger.critical("EXCEPTION:" + str(type(e))) self.__logger.critical(str(e)) self.__logger.critical("Stacktrace:" + str(traceback.format_exc())) raise PKVMError("CONTROLLER", "GETDISKS", "UNEXPECTED_GETDISKS") # getAvailableDisks() def diskSelection(self): """ Handles the Disk Selection screen @rtype: nothing @returns: nothing """ try: disks = self.getAvailableDisks() # no disk retrieved: log the error and exit if len(disks) == 0: #self.__viewer.getDiskSelectionError().showErrorNoDisk() self.__logger.critical('No disk found in the system. Exiting...') # Straight back to main menu raise PKVMError("CONTROLLER", "DISKSEL", "NO_DISK") self.__logger.info('Disks found: %s' % disks) while True: # run disk selection screen and get the user option detdisks = self.__partitioner.getDisks() lvmData = self.__partitioner.getLVMInfo() raidData = self.__partitioner.getRaidInfo() diskSelected = self.__viewer.getDiskSelection(disks, detdisks, lvmData, raidData).run() # no disk selected or back pressed: go back to main menu if diskSelected is None: return if disks[diskSelected][2] < 70: self.__viewer.getDiskSelectionError().showErrorDiskSize() # Try disk selection again continue disk = "/dev/%s" % diskSelected self.__logger.info('Disk selected %s' % disk) # call next screen res = self.installProgress(disk) if res == "back": continue break except PKVMError as e: raise except Exception as e: self.__logger.critical(STR_VERSION + ": Unexpected error while selecting disks.") self.__logger.critical("EXCEPTION:" + str(type(e))) self.__logger.critical(str(e)) self.__logger.critical("Stacktrace:" + str(traceback.format_exc())) raise PKVMError("CONTROLLER", "DISKSEL", "UNEXPECTED_DISKSEL") # diskSelection() def systemConfigure(self, diskSelected): """ Delegates the configuration phase to config controller in order to get user information about root pwd, timezone and network. @rtype: nothing @returns: nothing """ try: if self.__data['model'].get('action') not in ('install', 'upgrade', 'reinstall'): config = ConfController(self.__model, self.__viewer, self.__data) detdisks = self.__partitioner.getDisks() lvmData = self.__partitioner.getLVMInfo() res = config.wizard(diskSelected, detdisks, lvmData) if res == 'back': return res except PKVMError as e: raise except Exception as e: self.__logger.critical(STR_VERSION + ": Unexpected error while configuring system.") self.__logger.critical("EXCEPTION:" + str(type(e))) self.__logger.critical(str(e)) self.__logger.critical("Stacktrace:" + str(traceback.format_exc())) raise PKVMError("CONTROLLER", "SYSCONF", "UNEXPECTED_SYSCONF") # systemConfigure() def installProgress(self, diskSelected): """ Handles the Install screen @type diskSelected: str @param diskSelected: disk selected by user only used for install @rtype: nothing @returns: nothing """ reinstall = False # no particular disk select, reinstall if not diskSelected: reinstall = True diskSelected = VGROOT res = self.systemConfigure(diskSelected) if res == 'back': return res self.__logger.info('InstallProgress screen') # get the installer viewer install = self.__viewer.getInstallProgress() # get problems performing disk operations try: self.__logger.info('Formatting disks...') # reinstall process: reset root device and don't touch on other ones if self.__partitioner.detectedPreviousInstall() is True and reinstall: install.updateProgress(FORMATTING_ROOT_DEVICE_TO_REINSTALL.localize(), 0) self.__partitioner.resetRootDevice() # install process: create a default lvm layout on disk else: # format the disks install.updateProgress(FORMATTING_DISKS.localize(), 0) self.__partitioner.createDefaultLVMLayout(diskSelected.split('/')[-1], True) # some error handling disks: abort except PKVMError as e: #install.updateProgress(ERROR_WHILE_INSTALLING_IBM_POWERKVM.localize() % diskSelected, 30) raise except Exception as e: #install.updateProgress(ERROR_WHILE_INSTALLING_IBM_POWERKVM.localize() % diskSelected, 30) self.__logger.critical(STR_VERSION + ": Unexpected error while partitioning the disk.") self.__logger.critical("EXCEPTION:" + str(type(e))) self.__logger.critical(str(e)) self.__logger.critical("Stacktrace:" + str(traceback.format_exc())) raise PKVMError("CONTROLLER", "INSTALLPROGRESSPARTITIONER", "UNEXPECTED_PARTITIONER") # get prep, boot, root and log devices prep = self.__partitioner.getPrepDevice() boot = self.__partitioner.getBootDevice() root = self.__partitioner.getRootDevice() log = self.__partitioner.getLogDevice() data = self.__partitioner.getDataDevice() swap = self.__partitioner.getSwapDevice() self.__data['model'].insert('bootDevice', boot) try: # Copy root file system into the disk self.__logger.info("Installing IBM PowerKVM into disk %s..." % diskSelected) install.updateProgress(INSTALLING_IBM_POWERKVM_INTO_DISK.localize() % diskSelected, 25) installSystem(prep, boot, root, log, data, swap, install.installInfo, self.__partitioner.getMultipathMode()) except PKVMError as e: install.updateProgress(ERROR_WHILE_INSTALLING_IBM_POWERKVM.localize() % diskSelected, 30) raise except Exception as e: install.updateProgress(ERROR_WHILE_INSTALLING_IBM_POWERKVM.localize() % diskSelected, 30) self.__logger.critical(STR_VERSION + ": Unexpected error while installing packages.") self.__logger.critical("EXCEPTION:" + str(type(e))) self.__logger.critical(str(e)) self.__logger.critical("Stacktrace:" + str(traceback.format_exc())) raise PKVMError("CONTROLLER", "INSTALLPROGRESSPACKAGES", "UNEXPECTED_PACKAGES") try: # notifies EVT_POST_INSTALL self.__logger.info('System Installed. Starting post install scripts.') install.updateProgress(SYSTEM_INSTALLED_STARTING_POST.localize(), 100) self.__scriptController.notify(EVT_POST_INSTALL, self.__data) except PKVMError as e: raise except Exception as e: self.__logger.critical(STR_VERSION + ": Unexpected error while executing post-install modules.") self.__logger.critical("EXCEPTION:" + str(type(e))) self.__logger.critical(str(e)) self.__logger.critical("Stacktrace:" + str(traceback.format_exc())) raise PKVMError("CONTROLLER", "INSTALLPROGRESSPOSTINSTALL", "UNEXPECTED_POSTINSTALL") self.rebootSystem() # installProgress() def reinstallConfirmation(self, installed_disk=None): """ Handles the screen to confirm reinstall operation. @type installed_disk: Boolean @param installed_disk: The disk where PowerKVM was installed @rtype: None @return: Nothing """ self.__logger.info('Confirm reinstall screen') # show a message warning about wipe system and get confirmation installed_diskId = self.__partitioner.getDiskById(installed_disk).split('/')[-1] reinstallSystem = self.__viewer.getReinstallConfirmation(installed_diskId).run() # user does not desire reinstall system: back to main menu if reinstallSystem == 'no': return # call install screen, and don't care about disk because # reinstallation is a controlled process self.installProgress('') # reinstallConfirmation() def upgradeProgress(self, manual): """ Upgrades the hypervisor @type manual: bool @param manual: True if manual mode @rtype: nothing @returns: nothing """ self.__logger.info('UpgradeProgress screen') upgrade = self.__viewer.getUpgradeProgressScreen() # manual mode: if manual: if upgrade.showConfirmationBox(PROCEED_TO_UPGRADE_THE_SYSTEM.localize()) is False: # Back to main menu return # previous KoP system not installed: upgrade is not possible if self.__partitioner.detectedPreviousInstall() is False: self.__logger.critical("Cannot found installed system, upgrade is not possible!") upgrade.showMessageBox(ERROR_CANNOT_DETECT_INSTALLED_SYSTEM.localize()) # FIXME: Shed some light on what happened, before returning to main menu return installedVersion = self.__data['model'].get('version') # couldn't identify installed version: cannot upgrade if installedVersion is None: self.__logger.critical("Couldn't identify installed system version, cannot upgrade") upgrade.showMessageBox(ERROR_CANNOT_DETECT_INSTALLED_SYSTEM_VERSION.localize()) # FIXME: Should the upgrade option be removed from main menu, then ? return # installed version is newer than this current version: cannot upgrade elif installedVersion > VERSION: self.__logger.critical("Installed system is newer than the system in this package, cannot upgrade") upgrade.showMessageBox(ERROR_INSTALLED_SYSTEM_IS_NEWER.localize()) # FIXME: Should the upgrade option be removed from main menu, then ? return # installed version is too far behind (2 upgrades difference) the current # version: cannot upgrade elif installedVersion + 1 < VERSION: self.__logger.critical("Cannot fast forward two upgrades at onde") upgrade.showMessageBox(ERROR_CANNOT_FAST_FORWARD_UPGRADES.localize()) # FIXME: Should the upgrade option be removed from main menu, then ? return self.__logger.info("Starting upgrade...") upgrade.showUpgrade() # upgrade the system if upgradeSystem(ROOT_DEVICE, upgrade.upgradeInfo) is False: self.__logger.critical("Upgrade failed!") upgrade.showMessageBox(ERROR_UPGRADE_FAILED.localize()) # Back to main menu return self.__logger.info('System Upgraded. Starting post upgrade scripts.') upgrade.updateProgress(RUNNING_POST_UPGRADE_SCRIPTS.localize(), 90) # notifies EVT_POST_UPGRADE self.__scriptController.notify(EVT_POST_UPGRADE, self.__data) upgrade.updateProgress(UPGRADE_CONCLUDED.localize(), 100) self.__logger.info("Upgrade done") self.rebootSystem() # upgradeProgress() def rebootSystem(self, error=False): """ Handles the Reboot system screen @type error: boolean @param error: reboot due to error @rtype: nothing @returns: nothing """ self.__logger.info('RebootSystem screen') if error: self.__viewer.getRebootSystem().run(error) elif not self.__data['model'].get('action'): # Only show reboot message is NOT in auto mode # message user about rebooting self.__viewer.getRebootSystem().run() # reboot subprocess.call("reboot") # RebootSystem() def __createLog(self): """ Create log after install failure @rtype: nothing @returns: nothing """ separator = "====================" cmd = [] # General cmd.append("dmesg") cmd.append("systemctl status") cmd.append("journalctl -xb") cmd.append("cat /proc/cmdline") cmd.append("cat %s" % KICKSTART_FILE) # Network cmd.append("ifconfig -a") cmd.append("ip address") cmd.append("route -n") cmd.append("lspci -vv -k") cmd.append("ls -la /sys/class/net/") cmd.append("ls -la /sys/devices/virtual/net/") cmd.append("grep '' /sys/class/net/*/*") #cmd.append("cat /sys/class/net/*/carrier") #cmd.append("cat /sys/class/net/*/operstate") cmd.append("ls -la /etc/sysconfig/network-scripts/") cmd.append("cat /etc/sysconfig/network-scripts/ifcfg-*") # Disk cmd.append("iprconfig -c show-config") cmd.append("iprconfig -c show-alt-config") cmd.append("iprconfig -c show-ioas") cmd.append("multipath -l") cmd.append("dmsetup ls") cmd.append("pvscan") cmd.append("vgscan") cmd.append("lvscan") cmd.append("ls -la /dev/sd*") cmd.append("ls -la /dev/mapper/") cmd.append("ls -la /dev/disk/*") cmd.append("ls -la /dev/dm-*") with open(IBMPKVM_ERROR_LOG, "a") as f: for i in cmd: proc = Popen(i, shell=True, stdout=PIPE, stderr=PIPE) out, err = proc.communicate() msg = ">>> COMMAND: %s" % i exitCode = ">>> Exit Code: %s" % proc.returncode if proc.returncode != 0: exitCode = exitCode + "\n>>> Error messsage: %s" % err output = ">>> OUTPUT:\n%s" % out f.write("%s\n%s\n%s\n%s\n" % (separator, msg, exitCode, output)) tarCmd = "tar -zcvf %s %s %s %s" % (IBMPKVM_TARBALL_ERROR_LOG, IBMPKVM_ERROR_LOG, LIVECD_INSTALLER_LOG, LIVECD_PARTITIONER_LOG) proc = Popen(tarCmd.split(" "), stdout=PIPE, stderr=PIPE) out, err = proc.communicate()