def buildDeadmanDriver(): sgDriverDir = '/opt/cmcluster/drivers' logger = logging.getLogger("patchLogger") logger.info("Rebuilding and installing the deadman driver for the new kernel.") #Save the current working directory, so that we can return to it after building the driver. cwd = os.getcwd() try: os.chdir(sgDriverDir) except OSError as err: logger.error("Could not change into the deadman drivers directory (" + sgDriverDir + ").\n" + str(err)) print RED + "Could not change into the deadman drivers directory; check the log file for errors; the deadman driver will have to be manually built/installed." + RESETCOLORS return 'Failure' driverBuildCommandsList = ['make modules', 'make modules_install', 'depmod -a'] timeFeedbackThread = TimeFeedbackThread("Rebuilding and installing the deadman driver") timeFeedbackThread.start() for command in driverBuildCommandsList: buildCommand = command result = subprocess.Popen(buildCommand, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) out, err = result.communicate() logger.debug("The output of the command (" + command + ") used in building and installing the deadman driver was: " + out.strip()) if result.returncode != 0: timeFeedbackThread.stopTimer() timeFeedbackThread.join() logger.error("Failed to build and install the deadman driver.\n" + err) print RED + "Failed to build and install the deadman driver; check the log file for errors; the deadman driver will have to be manually built/installed." + RESETCOLORS return 'Failure' timeFeedbackThread.stopTimer() timeFeedbackThread.join() try: os.chdir(cwd) except: pass logger.info("Done rebuilding and installing the deadman driver for the new kernel.") return 'Success'
class ApplyPatches: """ Use the constructor to create a threading event that will be used to stop and restart the timer thread when a signal (SIGINT, SIGQUIT) is captured. Additionally, create the timer thread without a message, since it will be set later depending on the type of patches being applied. self.exitStatus is used to inform the caller as to whether or not the program needs to exit, which would be the case if self.exitStatus is not 0. """ def __init__(self): self.timerController = threading.Event() self.timeFeedbackThread = '' self.pid = '' self.exitStatus = 0 self.cancelled = 'no' def applyPatches(self, repositoryList, loggerName): logger = logging.getLogger(loggerName) if len(repositoryList) > 1: logger.info('Applying patches from repositories ' + ', '.join(repositoryList) + '.') else: logger.info('Applying patches from repository ' + repositoryList[0] + '.') logger.info('The patch repository list was determined to be: ' + str(repositoryList)) for repository in repositoryList: time.sleep(2) if 'kernel' in repository.lower(): self.timeFeedbackThread = TimeFeedbackThread(componentMessage='Installing the new kernel', event=self.timerController) self.timeFeedbackThread.start() command = 'zypper -n --non-interactive-include-reboot-patches --no-refresh in -r ' + repository + ' ' + repository + ':*' elif 'additional' not in repository.lower(): self.timeFeedbackThread = TimeFeedbackThread(componentMessage='Applying the OS patches', event=self.timerController) self.timeFeedbackThread.start() command = 'zypper -n --non-interactive-include-reboot-patches --no-refresh up -r ' + repository + ' ' + repository + ':*' result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=self.preexec, shell=True) self.pid = result.pid out, err = result.communicate() logger.info('The output of the patch update command (' + command + ') was: ' + out.strip()) if result.returncode == 0: logger.info('Successfully updated the system using patches from the repository ' + repository + '.') else: self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() print '' if self.cancelled == 'yes': logger.info('The patch update was cancelled by the user.') print RED + 'The patch update was cancelled; exiting program execution.' + RESETCOLORS else: logger.error('Problems were encountered while updating the system using patches from the repository ' + repository + '.\n' + err) print RED + 'Problems were encountered while applying the patches to the system; check the log file for errors; exiting program execution.' + RESETCOLORS self.exitStatus = 1 return self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() print '' if len(repositoryList) > 1: logger.info('Done applying patches from repositories ' + ', '.join(repositoryList) + '.') else: logger.info('Done applying patches from repository ' + repositoryList[0] + '.') def endTask(self): try: self.cancelled = 'yes' pgid = os.getpgid(self.pid) os.killpg(pgid, signal.SIGKILL) except OSError: pass def preexec(self): os.setpgrp() def getExitStatus(self): return self.exitStatus def pauseTimerThread(self): self.timeFeedbackThread.pauseTimer() def resumeTimerThread(self): self.timeFeedbackThread.resumeTimer()
class BuildDeadmanDriver: ''' Use the constructor to create a threading event that will be used to stop and restart the timer thread when a signal (SIGINT, SIGQUIT) is captured. ''' def __init__(self): self.timerController = threading.Event() self.timeFeedbackThread = TimeFeedbackThread(componentMessage = "Rebuilding and installing the deadman driver", event = self.timerController) self.pid = '' self.cancelled = 'no' self.completionStatus = '' #End __init__(self): ''' This function is used to configure the deadman driver on Serviceguard systems. ''' def buildDeadmanDriver(self, loggerName): sgDriverDir = '/opt/cmcluster/drivers' logger = logging.getLogger(loggerName) logger.info("Rebuilding and installing the deadman driver for the new kernel.") #Save the current working directory, so that we can return to it after building the driver. cwd = os.getcwd() try: os.chdir(sgDriverDir) except OSError as err: logger.error("Could not change into the deadman drivers directory (" + sgDriverDir + ").\n" + str(err)) print RED + "Could not change into the deadman drivers directory; check the log file for errors; the deadman driver will have to be manually built/installed." + RESETCOLORS self.completionStatus = 'Failure' return driverBuildCommandsList = ['make modules', 'make modules_install', 'depmod -a'] self.timeFeedbackThread.start() for command in driverBuildCommandsList: buildCommand = command result = subprocess.Popen(buildCommand, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=self.preexec, shell=True) #We get the processes PID in case the process is cancelled and we need to kill the process. self.pid = result.pid out, err = result.communicate() logger.debug("The output of the command (" + command + ") used in building and installing the deadman driver was: " + out.strip()) if result.returncode != 0: self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() #Move the cursor to the next line once the timer is stopped. print '' if self.cancelled == 'yes': logger.info("The deadman driver build and install was cancelled by the user.") print RED + "The deadman driver build and install was cancelled; the deadman driver will have to be manually built/installed." + RESETCOLORS else: logger.error("Failed to build and install the deadman driver.\n" + err) print RED + "Failed to build and install the deadman driver; check the log file for errors; the deadman driver will have to be manually built/installed." + RESETCOLORS self.completionStatus = 'Failure' return self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() #Move the cursor to the next line once the timer is stopped. print '' try: os.chdir(cwd) except: pass logger.info("Done rebuilding and installing the deadman driver for the new kernel.") self.completionStatus = 'Success' #End buildDeadmanDriver(loggerName): #This function will attempt to kill the running processes as requested by the user. def endTask(self): try: self.cancelled = 'yes' pgid = os.getpgid(self.pid) os.killpg(pgid, signal.SIGKILL) except OSError: pass #End endTask(self): ''' This function is used by subprocess so that signals are not propagated to the child process, which would result in the child process being cancelled without program control. ''' def preexec(self): os.setpgrp() #End preexec(self): #This function is used to get the completion status (Failure or Success) of the deadman build/install. def getCompletionStatus(self): return self.completionStatus #End getExitStatus(self): #This function is used to pause the timer thread when a signal is recieved. def pauseTimerThread(self): self.timeFeedbackThread.pauseTimer() #End pauseTimerThread(self): #This function is used to restart the timer thread once the signal has been handled. def resumeTimerThread(self): self.timeFeedbackThread.resumeTimer()
class UpdateFusionIO(): """ Use the constructor to create a threading event that will be used to stop and restart the timer thread when a signal (SIGINT, SIGQUIT) is captured. """ def __init__(self): self.timerController = threading.Event() self.timeFeedbackThread = '' self.pid = '' self.cancelled = 'no' self.completionStatus = '' def updateFusionIO(self, patchResourceDict, loggerName, **kwargs): firmwareUpdateRequired = kwargs['firmwareUpdateRequired'] iomemoryCfgBackup = kwargs['iomemory-vslBackup'] logger = logging.getLogger(loggerName) if firmwareUpdateRequired == 'yes': logger.info('Updating the FusionIO firmware and software.') busList = kwargs['busList'].split() else: logger.info('Updating the FusionIO software.') try: patchBaseDir = re.sub( '\\s+', '', patchResourceDict['patchBaseDir']).rstrip('/') fusionIOSubDir = re.sub('\\s+', '', patchResourceDict['fusionIOSubDir']) fusionPatchDir = patchBaseDir + '/' + fusionIOSubDir fusionSourceDir = fusionPatchDir + '/src/' fusionIODriverSrcRPM = re.sub( '\\s+', '', patchResourceDict['fusionIODriverSrcRPM']) except KeyError as err: logger.error('The resource key (' + str(err) + ') was not present in the resource file.') print RED + 'A resource key was not present in the resource file; check the log file for errors; the FusionIO firmware and software/driver will have to be updated manually.' + RESETCOLORS self.completionStatus = 'Failure' return command = 'uname -r' result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) out, err = result.communicate() logger.debug('The output of the command (' + command + ') used to get the currently used kernel was: ' + out.strip()) if result.returncode != 0: logger.error( "Unable to get the system's current kernel information.\n" + err) print RED + "Unable to get the system's current kernel information; check the log file for errors; the FusionIO firmware and software/driver will have to be updated manually." + RESETCOLORS self.completionStatus = 'Failure' return kernel = out.strip() command = 'uname -p' result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) out, err = result.communicate() logger.debug('The output of the command (' + command + ") used to get the system's processor type was: " + out.strip()) if result.returncode != 0: logger.error("Unable to get the system's processor type.\n" + err) print RED + "Unable to get the system's processor type; check the log file for errors; the FusionIO firmware and software/driver will have to be updated manually." + RESETCOLORS self.completionStatus = 'Failure' return processorType = out.strip() fusionIODriverRPM = fusionIODriverSrcRPM.replace( 'iomemory-vsl', '-vsl-' + kernel).replace('src', processorType) if firmwareUpdateRequired == 'yes': for bus in busList: time.sleep(2) message = 'Updating ioDIMM in slot ' + bus self.timeFeedbackThread = TimeFeedbackThread( componentMessage=message, event=self.timerController) self.timeFeedbackThread.start() command = 'fio-update-iodrive -y -f -s ' + bus + ' ' + fusionPatchDir + '/' + '*.fff' result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=self.preexec, shell=True) self.pid = result.pid out, err = result.communicate() logger.debug('The output of the command (' + command + ') used to update the FusionIO firmware was: ' + out.strip()) self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() print '' if result.returncode != 0: if self.cancelled == 'yes': logger.info( 'The FusionIO firmware update was cancelled by the user.' ) print RED + 'The FusionIO firmware update was cancelled; the FusionIO firmware and software/driver will have to be updated manually.' + RESETCOLORS else: logger.error( 'Failed to upgrade the FusionIO firmware:\n' + err) print RED + 'Failed to upgrade the FusionIO firmware; check the log file for errors; the FusionIO firmware and software/driver will have to be updated manually.' + RESETCOLORS self.completionStatus = 'Failure' return command = 'rpm -e fio-util' result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) out, err = result.communicate() logger.debug( 'The output of the command (' + command + ') used to remove the fio-util package before updating the FusionIO software was: ' + out.strip()) if result.returncode != 0: logger.error('Failed to remove the fio-util package:\n' + err) print RED + 'Failed to remove the fio-util package; check the log file for errors; the FusionIO software/driver will have to be updated manually.' + RESETCOLORS self.completionStatus = 'Failure' return self.timeFeedbackThread = TimeFeedbackThread( componentMessage='Updating the FusionIO driver and software', event=self.timerController) self.timeFeedbackThread.start() command = 'rpmbuild --rebuild ' + fusionSourceDir + '*.rpm' result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=self.preexec, shell=True) self.pid = result.pid out, err = result.communicate() logger.debug('The output of the command (' + command + ') used to build the FusionIO driver was: ' + out.strip()) if result.returncode != 0: self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() if self.cancelled == 'yes': logger.info( 'The FusionIO driver and software update was cancelled by the user.' ) print RED + '\nThe FusionIO driver and software update was cancelled; the FusionIO software/driver will have to be updated manually.' + RESETCOLORS else: logger.error('Failed to build the FusionIO driver:\n' + err) print RED + 'Failed to build the FusionIO driver; check the log file for errors; the FusionIO software/driver will have to be updated manually.' + RESETCOLORS self.completionStatus = 'Failure' return out = out.strip() fusionIODriverPattern = re.compile( '.*Wrote:\\s+((/[0-9,a-z,A-Z,_]+)+' + fusionIODriverRPM + ')', re.DOTALL) logger.debug( 'The regex used to get the FusionIO driver RPM location was: ' + fusionIODriverPattern.pattern) driverRPM = re.match(fusionIODriverPattern, out).group(1) logger.debug('The FuionIO driver was determined to be: ' + driverRPM) try: shutil.copy2(driverRPM, fusionPatchDir) except IOError as err: self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() print '' logger.error('Unable to retrieve the driver RPM.\n' + err) print RED + 'Unable to retrieve the driver RPM; check log file for errors; the FusionIO firmware and software/driver will have to be updated manually.' + RESETCOLORS self.completionStatus = 'Failure' return command = 'rpm -ivh ' + fusionPatchDir + '/' + '*.rpm' result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=self.preexec, shell=True) self.pid = result.pid out, err = result.communicate() logger.debug( 'The output of the command (' + command + ') used to install the FusionIO software and driver was: ' + out.strip()) if result.returncode != 0: self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() print '' if self.cancelled == 'yes': logger.info( 'The FusionIO driver and software installation was cancelled by the user.' ) print RED + 'The FusionIO driver and software installation was cancelled; the FusionIO software/driver will have to be installed manually from ' + fusionPatchDir + '.' + RESETCOLORS else: logger.error( 'Failed to install the FusionIO software and driver:\n' + err) print RED + 'Failed to install the FusionIO software and driver; check the log file for errors; the FusionIO software/driver will have to be installed manually from ' + fusionPatchDir + '.' + RESETCOLORS self.completionStatus = 'Failure' return try: shutil.copy2(iomemoryCfgBackup, '/etc/sysconfig/iomemory-vsl') except IOError as err: logger.error( "Failed to restore the system's iomemory-vsl configuration file.\n" + str(err)) print RED + "Failed to restore the system's iomemory-vsl configuration file; check the log file for errors; the file will need to be restored manually." + RESETCOLORS if firmwareUpdateRequired == 'yes': logger.info('Done Updating the FusionIO firmware and software.') else: logger.info('Done Updating the FusionIO software.') self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() print '' self.completionStatus = 'Success' def endTask(self): try: self.cancelled = 'yes' pgid = os.getpgid(self.pid) os.killpg(pgid, signal.SIGKILL) except OSError: pass def preexec(self): os.setpgrp() def getCompletionStatus(self): return self.completionStatus def pauseTimerThread(self): self.timeFeedbackThread.pauseTimer() def resumeTimerThread(self): self.timeFeedbackThread.resumeTimer()
class UpdateFusionIO: ''' Use the constructor to create a threading event that will be used to stop and restart the timer thread when a signal (SIGINT, SIGQUIT) is captured. ''' def __init__(self): self.timerController = Event() self.timeFeedbackThread = '' self.pid = 0 self.cancelled = 'no' self.completionStatus = '' self.fusionIOFirmwareUpdateStarted = False self.fusionIOFirmwareUpdateThreadList = [] def updateFusionIO(self, patchResourceDict, loggerName, **kwargs): firmwareUpdateRequired = kwargs['firmwareUpdateRequired'] iomemoryCfgBackup = kwargs['iomemory-vslBackup'] logger = logging.getLogger(loggerName) if firmwareUpdateRequired == 'yes': logger.info('Updating the FusionIO firmware and software.') busList = kwargs['busList'].split() else: logger.info('Updating the FusionIO software.') try: patchBaseDir = re.sub('\\s+', '', patchResourceDict['patchBaseDir']).rstrip('/') fusionIOSubDir = re.sub('\\s+', '', patchResourceDict['fusionIOSubDir']) fusionPatchDir = patchBaseDir + '/' + fusionIOSubDir fusionSourceDir = fusionPatchDir + '/src/' fusionIODriverSrcRPM = re.sub('\\s+', '', patchResourceDict['fusionIODriverSrcRPM']) except KeyError: err = None logger.error('The resource key (' + str(err) + ') was not present in the resource file.') print RED + 'A resource key was not present in the resource file; check the log file for errors; the FusionIO firmware and software/driver will have to be updated manually.' + RESETCOLORS self.completionStatus = 'Failure' return None command = 'uname -r' result = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True) (out, err) = result.communicate() logger.info('The output of the command (' + command + ') used to get the currently used kernel was: ' + out.strip()) if result.returncode != 0: logger.error("Unable to get the system's current kernel information.\n" + err) print RED + "Unable to get the system's current kernel information; check the log file for errors; the FusionIO firmware and software/driver will have to be updated manually." + RESETCOLORS self.completionStatus = 'Failure' return None kernel = None.strip() command = 'uname -p' result = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True) (out, err) = result.communicate() logger.info('The output of the command (' + command + ") used to get the system's processor type was: " + out.strip()) if result.returncode != 0: logger.error("Unable to get the system's processor type.\n" + err) print RED + "Unable to get the system's processor type; check the log file for errors; the FusionIO firmware and software/driver will have to be updated manually." + RESETCOLORS self.completionStatus = 'Failure' return None processorType = None.strip() fusionIODriverRPM = fusionIODriverSrcRPM.replace('iomemory-vsl', '-vsl-' + kernel).replace('src', processorType) if firmwareUpdateRequired == 'yes': message = 'Updating ioDIMM(s) ' + ', '.join(busList) self.timeFeedbackThread = TimeFeedbackThread(componentMessage = message, event = self.timerController) self.timeFeedbackThread.start() fusionIOFirmwareUpdateFailureList = [] self.fusionIOFirmwareUpdateStarted = True firmwareImage = fusionPatchDir + '/*.fff' for bus in busList: self.fusionIOFirmwareUpdateThreadList.append(FusionIOFirmwareUpdate(bus, firmwareImage, fusionIOFirmwareUpdateFailureList, loggerName)) self.fusionIOFirmwareUpdateThreadList[-1].start() while None: for i in range(0, len(self.fusionIOFirmwareUpdateThreadList)): if not self.fusionIOFirmwareUpdateThreadList[i].isAlive(): del self.fusionIOFirmwareUpdateThreadList[i] break continue if len(self.fusionIOFirmwareUpdateThreadList) == 0: break continue self.fusionIOFirmwareUpdateStarted = False self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() print '' if len(fusionIOFirmwareUpdateFailureList) > 0: if self.cancelled == 'yes': logger.info('The FusionIO firmware update was cancelled by the user.') print RED + 'The FusionIO firmware update was cancelled; the FusionIO firmware and software/driver will have to be updated manually.' + RESETCOLORS else: logger.error('Problems were encountered while updating the FusionIO firmware for the IODIMMS: ' + ', '.join(fusionIOFirmwareUpdateFailureList)) print RED + 'Failed to upgrade the FusionIO firmware; check the log file for errors; the FusionIO firmware and software/driver will have to be updated manually.' + RESETCOLORS self.completionStatus = 'Failure' return None command = None result = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True) (out, err) = result.communicate() logger.info('The output of the command (' + command + ') used to remove the fio-util package before updating the FusionIO software was: ' + out.strip()) if result.returncode != 0: logger.error('Failed to remove the fio-util package:\n' + err) print RED + 'Failed to remove the fio-util package; check the log file for errors; the FusionIO software/driver will have to be updated manually.' + RESETCOLORS self.completionStatus = 'Failure' return None self.timeFeedbackThread = TimeFeedbackThread(componentMessage = 'Updating the FusionIO driver and software', event = self.timerController) self.timeFeedbackThread.start() command = 'rpmbuild --rebuild ' + fusionSourceDir + '*.rpm' result = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE, preexec_fn = self.preexec, shell = True) self.pid = result.pid (out, err) = result.communicate() logger.info('The output of the command (' + command + ') used to build the FusionIO driver was: ' + out.strip()) if result.returncode != 0: self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() if self.cancelled == 'yes': logger.info('The FusionIO driver and software update was cancelled by the user.') print RED + '\nThe FusionIO driver and software update was cancelled; the FusionIO software/driver will have to be updated manually.' + RESETCOLORS else: logger.error('Failed to build the FusionIO driver:\n' + err) print RED + 'Failed to build the FusionIO driver; check the log file for errors; the FusionIO software/driver will have to be updated manually.' + RESETCOLORS self.completionStatus = 'Failure' return None out = None.strip() fusionIODriverPattern = re.compile('.*Wrote:\\s+((/[0-9,a-z,A-Z,_]+)+' + fusionIODriverRPM + ')', re.DOTALL) logger.info('The regex used to get the FusionIO driver RPM location was: ' + fusionIODriverPattern.pattern) driverRPM = re.match(fusionIODriverPattern, out).group(1) logger.info('The FuionIO driver was determined to be: ' + driverRPM) try: shutil.copy2(driverRPM, fusionPatchDir) except IOError: err = None self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() print '' logger.error('Unable to retrieve the driver RPM.\n' + err) print RED + 'Unable to retrieve the driver RPM; check log file for errors; the FusionIO firmware and software/driver will have to be updated manually.' + RESETCOLORS self.completionStatus = 'Failure' return None self.pid = 0 command = 'rpm -ivh ' + fusionPatchDir + '/' + '*.rpm' result = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE, preexec_fn = self.preexec, shell = True) self.pid = result.pid (out, err) = result.communicate() logger.info('The output of the command (' + command + ') used to install the FusionIO software and driver was: ' + out.strip()) if result.returncode != 0: self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() print '' if self.cancelled == 'yes': logger.info('The FusionIO driver and software installation was cancelled by the user.') print RED + 'The FusionIO driver and software installation was cancelled; the FusionIO software/driver will have to be installed manually from ' + fusionPatchDir + '.' + RESETCOLORS else: logger.error('Failed to install the FusionIO software and driver:\n' + err) print RED + 'Failed to install the FusionIO software and driver; check the log file for errors; the FusionIO software/driver will have to be installed manually from ' + fusionPatchDir + '.' + RESETCOLORS self.completionStatus = 'Failure' return None shutil.copy2(iomemoryCfgBackup, '/etc/sysconfig/iomemory-vsl') else: except IOError: err = None logger.error("Failed to restore the system's iomemory-vsl configuration file.\n" + str(err)) print RED + "Failed to restore the system's iomemory-vsl configuration file; check the log file for errors; the file will need to be restored manually." + RESETCOLORS if firmwareUpdateRequired == 'yes': logger.info('Done Updating the FusionIO firmware and software.') else: logger.info('Done Updating the FusionIO software.') self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() print '' self.completionStatus = 'Success'
class ApplyPatches: ''' Use the constructor to create a threading event that will be used to stop and restart the timer thread when a signal (SIGINT, SIGQUIT) is captured. Additionally, create the timer thread without a message, since it will be set later depending on the type of patches being applied. self.exitStatus is used to inform the caller as to whether or not the program needs to exit, which would be the case if self.exitStatus is not 0. ''' def __init__(self): self.timerController = threading.Event() self.timeFeedbackThread = '' self.pid = '' self.exitStatus = 0 self.cancelled = 'no' #End __init__(self): ''' This function is used to apply the patches. ''' def applyPatches(self, repositoryList, loggerName): logger = logging.getLogger(loggerName) if len(repositoryList) > 1: logger.info('Applying patches from repositories ' + ', '.join(repositoryList) + '.') else: logger.info('Applying patches from repository ' + repositoryList[0] + '.') logger.debug("The patch repository list was determined to be: " + str(repositoryList)) #Update OS patches and install kernel patches. for repository in repositoryList: time.sleep(2) if 'kernel' in repository.lower(): self.timeFeedbackThread = TimeFeedbackThread( componentMessage='Installing the new kernel', event=self.timerController) self.timeFeedbackThread.start() command = 'zypper -n --non-interactive-include-reboot-patches in ' + repository + ':*' else: self.timeFeedbackThread = TimeFeedbackThread( componentMessage='Applying the OS patches', event=self.timerController) self.timeFeedbackThread.start() command = 'zypper -n --non-interactive-include-reboot-patches up ' + repository + ':*' result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=self.preexec, shell=True) #We get the processes PID in case the process is cancelled and we need to kill the process. self.pid = result.pid out, err = result.communicate() logger.debug("The output of the patch update command (" + command + ") was: " + out.strip()) if result.returncode == 0: logger.info( "Successfully updated the system using patches from the repository " + repository + ".") else: self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() #Move the cursor to the next line once the timer is stopped. print '' if self.cancelled == 'yes': logger.info("The patch update was cancelled by the user.") print RED + "The patch update was cancelled; exiting program execution." + RESETCOLORS else: logger.error( "Problems were encountered while updating the system using patches from the repository " + repository + ".\n" + err) print RED + "Problems were encountered while applying the patches to the system; check the log file for errors; exiting program execution." + RESETCOLORS self.exitStatus = 1 return self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() #Move the cursor to the next line once the timer is stopped. print '' if len(repositoryList) > 1: logger.info('Done applying patches from repositories ' + ', '.join(repositoryList) + '.') else: logger.info('Done applying patches from repository ' + repositoryList[0] + '.') #End applyPatches(repositoryList, loggerName): #This function will attempt to kill the running processes as requested by the user. def endTask(self): try: self.cancelled = 'yes' pgid = os.getpgid(self.pid) os.killpg(pgid, signal.SIGKILL) except OSError: pass #End endTask(self): ''' This function is used by subprocess so that signals are not propagated to the child process, which would result in the child process being cancelled without program control. ''' def preexec(self): os.setpgrp() #End preexec(self): #This function is used to get the exit status of the patch update. def getExitStatus(self): return self.exitStatus #End getExitStatus(self): #This function is used to pause the timer thread when a signal is recieved. def pauseTimerThread(self): self.timeFeedbackThread.pauseTimer() #End pauseTimerThread(self): #This function is used to restart the timer thread once the signal has been handled. def resumeTimerThread(self): self.timeFeedbackThread.resumeTimer()
class BuildDeadmanDriver: """ Use the constructor to create a threading event that will be used to stop and restart the timer thread when a signal (SIGINT, SIGQUIT) is captured. """ def __init__(self): self.timerController = threading.Event() self.timeFeedbackThread = TimeFeedbackThread( componentMessage='Rebuilding and installing the deadman driver', event=self.timerController) self.pid = '' self.cancelled = 'no' self.completionStatus = '' def buildDeadmanDriver(self, loggerName): sgDriverDir = '/opt/cmcluster/drivers' logger = logging.getLogger(loggerName) logger.info( 'Rebuilding and installing the deadman driver for the new kernel.') cwd = os.getcwd() try: os.chdir(sgDriverDir) except OSError as err: logger.error( 'Could not change into the deadman drivers directory (' + sgDriverDir + ').\n' + str(err)) print RED + 'Could not change into the deadman drivers directory; check the log file for errors; the deadman driver will have to be manually built/installed.' + RESETCOLORS self.completionStatus = 'Failure' return driverBuildCommandsList = [ 'make modules', 'make modules_install', 'depmod -a' ] self.timeFeedbackThread.start() for command in driverBuildCommandsList: buildCommand = command result = subprocess.Popen(buildCommand, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=self.preexec, shell=True) self.pid = result.pid out, err = result.communicate() logger.debug( 'The output of the command (' + command + ') used in building and installing the deadman driver was: ' + out.strip()) if result.returncode != 0: self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() print '' if self.cancelled == 'yes': logger.info( 'The deadman driver build and install was cancelled by the user.' ) print RED + 'The deadman driver build and install was cancelled; the deadman driver will have to be manually built/installed.' + RESETCOLORS else: logger.error( 'Failed to build and install the deadman driver.\n' + err) print RED + 'Failed to build and install the deadman driver; check the log file for errors; the deadman driver will have to be manually built/installed.' + RESETCOLORS self.completionStatus = 'Failure' return self.timeFeedbackThread.stopTimer() self.timeFeedbackThread.join() print '' try: os.chdir(cwd) except: pass logger.info( 'Done rebuilding and installing the deadman driver for the new kernel.' ) self.completionStatus = 'Success' def endTask(self): try: self.cancelled = 'yes' pgid = os.getpgid(self.pid) os.killpg(pgid, signal.SIGKILL) except OSError: pass def preexec(self): os.setpgrp() def getCompletionStatus(self): return self.completionStatus def pauseTimerThread(self): self.timeFeedbackThread.pauseTimer() def resumeTimerThread(self): self.timeFeedbackThread.resumeTimer()
def updateFusionIO(patchResourceDict, **kwargs): firmwareUpdateRequired = kwargs['firmwareUpdateRequired'] logger = logging.getLogger("patchLogger") if firmwareUpdateRequired == 'yes': logger.info("Updating the FusionIO firmware and software.") busList = (kwargs['busList']).split() else: logger.info("Updating the FusionIO software.") try: patchBaseDir = (re.sub('\s+', '', patchResourceDict['patchBaseDir'])).rstrip('/') fusionIOSubDir = re.sub('\s+', '', patchResourceDict['fusionIOSubDir']) fusionPatchDir = patchBaseDir + '/' + fusionIOSubDir fusionSourceDir = fusionPatchDir + '/src/' fusionIODriverSrcRPM = re.sub('\s+', '', patchResourceDict['fusionIODriverSrcRPM']) except KeyError as err: logger.error("The resource key (" + str(err) + ") was not present in the resource file.") print RED + "A resource key was not present in the resource file; check the log file for errors; the FusionIO firmware and software/driver will have to be updated manually." + RESETCOLORS return 'Failure' #Get the currently used kernel and processor type, which is used as part of the driver RPM name. command = 'uname -r' result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) out, err = result.communicate() logger.debug("The output of the command (" + command + ") used to get the currently used kernel was: " + out.strip()) if result.returncode != 0: logger.error("Unable to get the system's current kernel information.\n" + err) print RED + "Unable to get the system's current kernel information; check the log file for errors; the FusionIO firmware and software/driver will have to be updated manually." + RESETCOLORS return else: kernel = out.strip() command = 'uname -p' result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) out, err = result.communicate() logger.debug("The output of the command (" + command + ") used to get the system's processor type was: " + out.strip()) if result.returncode != 0: logger.error("Unable to get the system's processor type.\n" + err) print RED + "Unable to get the system's processor type; check the log file for errors; the FusionIO firmware and software/driver will have to be updated manually." + RESETCOLORS return 'Failure' else: processorType = out.strip() ''' This strips off iomemory from RPM name, since it will not be needed in the regex match. Additionally, the source RPM is renamed to the driver RPM's name, which includes the current kernel and processor type in its name. ''' fusionIODriverRPM = (fusionIODriverSrcRPM.replace('iomemory-vsl', '-vsl-' + kernel)).replace('src', processorType) #Update the FusionIO firmware if it was determined that it is out of date. if firmwareUpdateRequired == 'yes': #Set traps so that the firmware update is not interrupted by the user. original_sigint_handler = signal.getsignal(signal.SIGINT) original_sigquit_handler = signal.getsignal(signal.SIGQUIT) signal.signal(signal.SIGINT, firmware_signal_handler) signal.signal(signal.SIGQUIT, firmware_signal_handler) for bus in busList: time.sleep(2) timeFeedbackThread = TimeFeedbackThread("Updating ioDIMM in slot", bus) timeFeedbackThread.start() command = "fio-update-iodrive -y -f -s " + bus + ' ' + fusionPatchDir + '/' + "*.fff" result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) out, err = result.communicate() logger.debug("The output of the command (" + command + ") used to update the FusionIO firmware was: " + out.strip()) timeFeedbackThread.stopTimer() timeFeedbackThread.join() if result.returncode != 0: logger.error("Failed to upgrade the FusionIO firmware:\n" + err) print RED + "Failed to upgrade the FusionIO firmware; check the log file for errors; the FusionIO firmware and software/driver will have to be updated manually." + RESETCOLORS signal.signal(signal.SIGINT, original_sigint_handler) signal.signal(signal.SIGQUIT, original_sigquit_handler) return 'Failure' #Restore the signals back to their defaults. signal.signal(signal.SIGINT, original_sigint_handler) signal.signal(signal.SIGQUIT, original_sigquit_handler) #Remove the fio-util package before updating the software, since it is no longer needed for any firmware updates. command = "rpm -e fio-util" result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) out, err = result.communicate() logger.debug("The output of the command (" + command + ") used to remove the fio-util package before updating the FusionIO software was: " + out.strip()) if result.returncode != 0: logger.error("Failed to remove the fio-util package:\n" + err) print RED + "Failed to remove the fio-util package; check the log file for errors; the FusionIO software/driver will have to be updated manually." + RESETCOLORS return 'Failure' #Build the driver for the new kernel. timeFeedbackThread = TimeFeedbackThread("Updating the FusionIO driver and software") timeFeedbackThread.start() command = "rpmbuild --rebuild " + fusionSourceDir + "*.rpm" result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) out, err = result.communicate() logger.debug("The output of the command (" + command + ") used to build the FusionIO driver was: " + out.strip()) if result.returncode != 0: timeFeedbackThread.stopTimer() timeFeedbackThread.join() logger.error("Failed to build the FusionIO driver:\n" + err) print RED + "Failed to build the FusionIO driver; check the log file for errors; the FusionIO software/driver will have to be updated manually." + RESETCOLORS return 'Failure' out = out.strip() #Compile the regex that will be used to get the driver RPM location. fusionIODriverPattern = re.compile('.*Wrote:\s+((/[0-9,a-z,A-Z,_]+)+' + fusionIODriverRPM +')', re.DOTALL) logger.debug("The regex used to get the FusionIO driver RPM location was: " + fusionIODriverPattern.pattern) driverRPM = re.match(fusionIODriverPattern, out).group(1) logger.debug("The FuionIO driver was determined to be: " + driverRPM) #Now copy the new driver RPM to the FusionIO patch directory so that it gets installed with the rest of the RPMs. try: shutil.copy2(driverRPM, fusionPatchDir) except IOError as err: timeFeedbackThread.stopTimer() timeFeedbackThread.join() logger.error("Unable to retrieve the driver RPM.\n" + err) print RED + "Unable to retrieve the driver RPM; check log file for errors; the FusionIO firmware and software/driver will have to be updated manually." + RESETCOLORS return 'Failure' #Update the FusionIO software. command = "rpm -ivh " + fusionPatchDir + '/' + "*.rpm" result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) out, err = result.communicate() logger.debug("The output of the command (" + command + ") used to update the FusionIO software was: " + out.strip()) if result.returncode != 0: timeFeedbackThread.stopTimer() timeFeedbackThread.join() logger.error("Failed to update the FusionIO software:\n" + err) print RED + "Failed to update the FusionIO software; check the log file for errors; the FusionIO software/driver will have to be updated manually." + RESETCOLORS return 'Failure' if firmwareUpdateRequired == 'yes': logger.info("Done Updating the FusionIO firmware and software.") else: logger.info("Done Updating the FusionIO software.") timeFeedbackThread.stopTimer() timeFeedbackThread.join() return 'Success'