예제 #1
0
def main():
    if os.geteuid() != 0:
        print RED + 'You must be root to run this program; exiting program execution.' + RESETCOLORS
        exit(1)
    programVersion = '1.4-1'
    usage = 'usage: %prog [[-h] [-r] [-s] [-u] [-v]]'
    parser = optparse.OptionParser(usage = usage)
    parser.add_option('-r', action = 'store_true', default = False, help = 'This option is used to generate a version report.')
    parser.add_option('-s', action = 'store_true', default = False, help = 'This option is used when upgrading Servicegaurd nodes to indicate which node is the primary node; the secondary node should already be upgraded before envoking this option.')
    parser.add_option('-u', action = 'store_true', default = False, help = 'This option is used to update the local OS hard drives before the mirror is split.')
    parser.add_option('-v', action = 'store_true', default = False, help = "This option is used to display the application's version.")
    (options, args) = parser.parse_args()
    if options.v:
        print os.path.basename(sys.argv[0]) + ' ' + programVersion
        exit(0)
    if not options.r or options.u:
        if (options.r or options.s or options.s) and options.u:
            print RED + "Options 'r', 's', and 'u' are mutually exclusive; please try again; exiting program execution." + RESETCOLORS
            exit(1)
        if options.r:
            versionInformationLogOnly = True
        else:
            versionInformationLogOnly = False
    if options.u:
        updateOSHarddrives = True
    else:
        updateOSHarddrives = False
    if options.s:
        command = 'dmidecode -s system-product-name'
        result = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)
        (out, err) = result.communicate()
        out = out.strip()
        if result.returncode != 0:
            print RED + "Unable to get the system's model information (dmidecode -s system-product-name); exiting program execution." + RESETCOLORS
            exit(1)
        
        try:
            systemModel = re.match('[a-z,0-9]+\\s+(.*)', out, re.IGNORECASE).group(1).replace(' ', '')
        except AttributeError:
            err = None
            print RED + "There was a system model match error when trying to match against '" + out + "':\n" + str(err) + '.' + RESETCOLORS
            exit(1)

        if systemModel != 'DL380pGen8' and systemModel != 'DL360pGen8':
            print RED + "The '-s' option can only be used on NFS Serviceguard systems (DL380pGen8 or DL360pGen8)." + RESETCOLORS
            exit(1)
        
    csurBasePath = '/hp/support/csur'
    currentLogDir = datetime.datetime.now().strftime('Date_%d%H%M%S%b%Y')
    logBaseDir = csurBasePath + '/log/' + currentLogDir + '/'
    sessionScreenLog = logBaseDir + 'sessionScreenLog.log'
    cursesLog = logBaseDir + 'cursesLog.log'
    
    try:
        os.mkdir(logBaseDir)
    except OSError:
        err = None
        print RED + 'Unable to create the current log directory ' + logBaseDir + '; fix the problem and try again; exiting program execution.\n' + str(err) + RESETCOLORS
        exit(1)

    
    try:
        cursesThread = CursesThread(sessionScreenLog, cursesLog)
        cursesThread.daemon = True
        cursesThread.start()
        initialize = Initialize(cursesThread)
        csurResourceDict = initialize.init(csurBasePath, logBaseDir, programVersion, versionInformationLogOnly, updateOSHarddrives)
        if options.s:
            csurResourceDict['sgNode1'] = True
        else:
            csurResourceDict['sgNode1'] = False
        if options.r:
            cursesThread.insertMessage([
                'informative',
                'The system version report has been created and is in the log directory.'])
            cursesThread.insertMessage([
                'info',
                ' '])
            if len(csurResourceDict['hardDrivesMissingFirmware']) != 0:
                cursesThread.insertMessage([
                    'warning',
                    'Hard drive firmware was missing for the following hard drives: ' + csurResourceDict['hardDrivesMissingFirmware'] + '; make sure to file a bug report.'])
                cursesThread.insertMessage([
                    'info',
                    ' '])
            
        elif len(csurResourceDict['componentListDict']['computeNodeList']) == 0 and len(csurResourceDict['hardDrivesMissingFirmware']) != 0:
            cursesThread.insertMessage([
                'error',
                "The compute node's local OS hard drives are not being updated, since firmware for the hard drives was missing."])
            cursesThread.insertMessage([
                'info',
                ' '])
            cursesThread.insertMessage([
                'error',
                'Hard drive firmware was missing for the following hard drives: ' + csurResourceDict['hardDrivesMissingFirmware'] + '; make sure to file a bug report.'])
        elif len(csurResourceDict['componentListDict']['computeNodeList']) == 0:
            cursesThread.insertMessage([
                'informative',
                'The compute node is already up to date; no action taken.'])
        else:
            timerThreadLocation = 1
            computeNodeDict = csurResourceDict['componentListDict']['computeNodeList'][0].getComputeNodeDict()
            hostname = computeNodeDict['hostname']
            if updateOSHarddrives:
                cursesThread.insertMessage([
                    'informative',
                    'Phase 2: Updating compute node ' + hostname + "'s hard drives that need to be updated."])
            elif len(csurResourceDict['hardDrivesMissingFirmware']) != 0:
                cursesThread.insertMessage([
                    'warning',
                    'Phase 2: Updating the compute node ' + hostname + "'s components that need to be updated, however, hard drive firmware was missing for the following hard drives: " + csurResourceDict['hardDrivesMissingFirmware'] + '; make sure to file a bug report.'])
            else:
                cursesThread.insertMessage([
                    'informative',
                    'Phase 2: Updating the compute node ' + hostname + "'s components that need to be updated."])
            computeNodeUpdate = ComputeNodeUpdate(cursesThread, csurResourceDict.copy(), timerThreadLocation)
            original_sigint_handler = signal.getsignal(signal.SIGINT)
            original_sigquit_handler = signal.getsignal(signal.SIGQUIT)
            s = SignalHandler(cursesThread)
            signal.signal(signal.SIGINT, s.signal_handler)
            signal.signal(signal.SIGQUIT, s.signal_handler)
            workerThread = Thread(target = computeNodeUpdate.updateComputeNodeComponents)
            workerThread.start()
            while None:
                if not workerThread.is_alive():
                    break
                response = s.getResponse()
                if response != '' or response == 'y':
                    computeNodeUpdate.endTask()
                    cursesThread.join()
                    exit(1)
                
            signal.signal(signal.SIGINT, original_sigint_handler)
            signal.signal(signal.SIGQUIT, original_sigquit_handler)
            componentProblemDict = computeNodeUpdate.getUpdateComponentProblemDict()
            if not updateOSHarddrives:
                updateVersionInformationFileResult = updateVersionInformationFile(csurResourceDict.copy())
            cursesThread.insertMessage([
                'info',
                ' '])
            if len(componentProblemDict['Software']) == 0 and len(componentProblemDict['Drivers']) == 0 and len(componentProblemDict['Firmware']) == 0:
                if not updateOSHarddrives:
                    if not updateVersionInformationFileResult:
                        cursesThread.insertMessage([
                            'warning',
                            'The update of compute node ' + hostname + ' completed succesfully, however, the version information file update failed; check the log file for errors and update the file manually.'])
                        cursesThread.insertMessage([
                            'info',
                            ' '])
                        if computeNodeDict['externalStoragePresent']:
                            cursesThread.insertMessage([
                                'final',
                                'Once the version information file is updated, power cycle the attached storage controller(s) and reboot the system for the changes to take effect.'])
                        else:
                            cursesThread.insertMessage([
                                'final',
                                'Once the version information file is updated, reboot the system for the changes to take effect.'])
                    else:
                        cursesThread.insertMessage([
                            'informative',
                            'The update of compute node ' + hostname + ' completed succesfully.'])
                        cursesThread.insertMessage([
                            'info',
                            ' '])
                        if computeNodeDict['externalStoragePresent']:
                            cursesThread.insertMessage([
                                'final',
                                'Power cycle the attached storage controller(s) and reboot the system for the changes to take effect.'])
                        else:
                            cursesThread.insertMessage([
                                'final',
                                'Reboot the system for the changes to take effect.'])
                else:
                    cursesThread.insertMessage([
                        'informative',
                        'The update of compute node ' + hostname + ' completed succesfully.'])
                    cursesThread.insertMessage([
                        'info',
                        ' '])
                    cursesThread.insertMessage([
                        'final',
                        'Reboot the system for the changes to take effect.'])
            elif not updateOSHarddrives:
                errorMessage = 'The following components encountered errors during the update of compute node ' + hostname + '; check the log file for errors:\n'
                if len(componentProblemDict['Software']) != 0:
                    if 'rpmRemovalFailure' not in componentProblemDict['Software']:
                        errorMessage += 'Software: ' + ', '.join(componentProblemDict['Software'].keys()) + '\n'
                    elif len(componentProblemDict['Software']) == 1:
                        errorMessage += 'Software: ' + componentProblemDict['Software']['rpmRemovalFailure'] + '\n'
                    else:
                        errorMessage += 'Software: ' + componentProblemDict['Software']['rpmRemovalFailure'] + ', '
                        del componentProblemDict['Software']['rpmRemovalFailure']
                        errorMessage += ', '.join(componentProblemDict['Software'].keys()) + '\n'
                if len(componentProblemDict['Drivers']) != 0:
                    errorMessage += 'Drivers: ' + ', '.join(componentProblemDict['Drivers'].keys()) + '\n'
                if len(componentProblemDict['Firmware']) != 0:
                    errorMessage += 'Firmware: ' + ', '.join(componentProblemDict['Firmware'].keys()) + '\n'
                if not updateVersionInformationFileResult:
                    errorMessage += 'Also, the version information file update failed; check the log file for errors and update the file manually.'
                cursesThread.insertMessage([
                    'error',
                    errorMessage])
            else:
                cursesThread.insertMessage([
                    'error',
                    'Errors were encountered while updating compute node ' + hostname + "'s hard drive firmware; check the log file for errors."])
        cursesThread.insertMessage([
            'info',
            ' '])
        cursesThread.getUserInput([
            'informative',
            'Press enter to exit.'])
        while not cursesThread.isUserInputReady():
            time.sleep(0.1)
    except Exception:
        cursesThread.join()
        traceback.print_exc()
        exit(1)
    finally:
        cursesThread.join()
예제 #2
0
def main():
    programVersion = '2018.03-0'
    addOnSoftwareInstalled = False
    hanaPartitionsRestored = False
    scaleUpSystem = False
    errorMessageList = []
    if os.geteuid() != 0:
        print RED + 'You must be root to run this program; exiting program execution.' + RESETCOLORS
        exit(1)
    usage = 'usage: %prog [[-h] [-p] [-v]]'
    parser = optparse.OptionParser(usage = usage)
    parser.add_option('-p', action = 'store_true', default = False, help = 'This option should be ran from the primary NFS Serviceguard node after the upgrade of both nodes when the upgrade caused the NIC cards to be renamed on one or both of the NFS Serviceguard nodes.')
    parser.add_option('-v', action = 'store_true', default = False, help = "This option is used to display the application's version.")
    (options, args) = parser.parse_args()
    programName = os.path.basename(sys.argv[0])
    if options.v:
        print programName + ' ' + programVersion
        exit(0)
    (osDist, osDistLevel) = getOSDistribution()
    upgradeLogDir = '/var/log/CoESapHANA_' + osDist + '_UpgradeLogDir'
    if not os.path.isdir(upgradeLogDir):
        
        try:
            os.mkdir(upgradeLogDir)
        except OSError:
            err = None
            print RED + "Unable to create the post upgrade log directory '" + upgradeLogDir + "'; fix the problem and try again; exiting program execution.\n" + str(err) + RESETCOLORS
            exit(1)
        

    dateTimestamp = datetime.datetime.now().strftime('%d%H%M%b%Y')
    logFile = upgradeLogDir + '/' + osDist + '_Post_Upgrade_' + dateTimestamp + '.log'
    handler = logging.FileHandler(logFile)
    logger = logging.getLogger('coeOSUpgradeLogger')
    logger.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(message)s', datefmt = '%m/%d/%Y %H:%M:%S')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    logger.info('The current version of the program is: ' + programVersion + '.')
    serverModel = getServerModel()
    if 'DL580' in serverModel:
        processor = getProcessorType()
    if options.p:
        if not 'DL380p' in serverModel or 'DL360p' in serverModel:
            print RED + "The '-p' option is only for Serviceguard NFS servers; exiting program execution." + RESETCOLORS
            exit(1)
        updateClusterCfg()
    else:
        
        try:
            programParentDir = ''
            cwd = os.getcwd()
            programParentDir = os.path.dirname(os.path.realpath(__file__))
            if cwd != programParentDir:
                os.chdir(programParentDir)
        except OSError:
            err = None
            logger.error("Unable to change into the programs parent directory '" + programParentDir + "'.\n" + str(err))
            print RED + "Unable to change into the programs parent directory '" + programParentDir + "'; fix the problem and try again; exiting program execution." + RESETCOLORS
            exit(1)

        if osDist == 'SLES':
            checkNetworkConfiguration = checkSLESNetworkConfiguration
            import modules.upgradeMisc
        else:
            checkNetworkConfiguration = checkRHELNetworkConfiguration
            import modules.upgradeMisc
        if 'DL580' in serverModel or serverModel == 'Superdome':
            if osDist == 'SLES':
                updateOSSettings = updateSLESOSSettings
                import modules.sapHANANodeSpec
            else:
                updateOSSettings = updateRHELOSSettings
                import modules.sapHANANodeSpec
        if 'DL580' in serverModel:
            command = 'cat /proc/scsi/scsi'
            result = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)
            (out, err) = result.communicate()
            out = out.strip()
            if result.returncode != 0:
                logger.error('Unable to determine if the DL580 is a Scale-up.\n' + str(out) + '\n' + str(err))
                print RED + 'Unable to determine if the DL580 is a Scale-up; fix the problem and try again; exiting program execution.' + RESETCOLORS
                exit(1)
            searchResult = re.search('P830i', out, re.MULTILINE | re.DOTALL)
            if not searchResult == None:
                globalIni = 'global.ini'
                globalIniList = []
                scaleOutSystem = False
                for (root, dirs, files) in os.walk(programParentDir):
                    if globalIni in files:
                        globalIniList.append(root + '/' + globalIni)
                        continue
                for file in globalIniList:
                    with open(file, 'r') as f:
                        data = f.read()
                        if re.match('.*log|data_{1,}wwid\\s*=\\s*360002ac0+', data, re.MULTILINE | re.DOTALL) != None:
                            scaleOutSystem = True
                            multipathArguments = [
                                'enable',
                                'start']
                            for argument in multipathArguments:
                                command = 'systemctl ' + argument + ' multipathd'
                                result = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)
                                (out, err) = result.communicate()
                                out = out.strip()
                                if result.returncode != 0:
                                    logger.error('Unable to ' + argument + ' multipathd.\n' + str(out) + '\n' + str(err))
                                    print RED + 'Unable to ' + argument + ' multipathd; fix the problem and try again; exiting program execution.' + RESETCOLORS
                                    exit(1)
                                time.sleep(0.1)
                            
                            break
                
                if not scaleOutSystem:
                    scaleUpSystem = True
                
            
        upgradeResourceDict = { }
        
        try:
            with open('upgradeResourceFile') as f:
                for line in f:
                    line = line.strip()
                    if len(line) == 0 and re.match('^\\s*#', line) or re.match('^\\s+$', line):
                        continue
                        continue
                    line = re.sub('[\'"]', '', line)
                    (key, val) = line.split('=')
                    key = key.strip()
                    upgradeResourceDict[key] = re.sub('\\s*,\\s*', ',', val).strip()
        except IOError:
            err = None
            logger.error("Unable to access the application's resource file 'upgradeResourceFile'.\n" + str(err))
            print RED + "Unable to access the application's resource file 'upgradeResourceFile'; fix the problem and try again; exiting program execution." + RESETCOLORS
            exit(1)

        sessionScreenLog = upgradeLogDir + '/sessionScreenLog.log'
        cursesLog = upgradeLogDir + '/cursesLog.log'
        
        try:
            cursesThread = CursesThread(sessionScreenLog, cursesLog)
            cursesThread.daemon = True
            cursesThread.start()
            osRestorationArchiveErrorFile = upgradeLogDir + '/.osRestorationArchiveError'
            if not os.path.isfile(osRestorationArchiveErrorFile):
                
                try:
                    os.mknod(osRestorationArchiveErrorFile)
                except OSError:
                    err = None
                    logger.error("Unable to create the OS restoration archive error file '" + osRestorationArchiveErrorFile + "'.\n" + str(err))
                    displayErrorMessage("Unable to create the OS restoration archive error file '" + osRestorationArchiveErrorFile + "'; fix the problem and try again.", cursesThread)
                

            progressStatusFile = upgradeLogDir + '/.restorationProgress'
            
            try:
                if os.path.isfile(progressStatusFile):
                    with open(progressStatusFile) as f:
                        progressDict = dict.fromkeys(lambda .0: continue(f))
                else:
                    progressDict = { }
                if os.path.isfile(progressStatusFile):
                    f = open(progressStatusFile, 'a')
                else:
                    f = open(progressStatusFile, 'w')
                osRestorationArchiveExtracted = False
                
                try:
                    if os.stat(osRestorationArchiveErrorFile).st_size < 50 and 'osRestorationArchiveExtracted' not in progressDict:
                        cursesThread.insertMessage([
                            'informative',
                            'Checking and extracting the OS restoration archive file.'])
                        cursesThread.insertMessage([
                            'informative',
                            ''])
                        osRestorationArchive = checkOSRestorationArchive(programParentDir, osRestorationArchiveErrorFile, osDist, cursesThread)
                        extractOSRestorationArchive(osRestorationArchive, osRestorationArchiveErrorFile, cursesThread)
                        f.write('osRestorationArchiveExtracted\n')
                        osRestorationArchiveExtracted = True
                except OSError:
                    err = None
                    logger.error("Unable to access the OS restoration archive error file '" + osRestorationArchiveErrorFile + "'.\n" + str(err))
                    displayErrorMessage("Unable to access the OS restoration archive error file '" + osRestorationArchiveErrorFile + "'; fix the problem and try again.", cursesThread)

                if os.path.isdir(programParentDir + '/addOnSoftwareRPMS'):
                    if 'installaddOnSoftware' not in progressDict:
                        f.write('installaddOnSoftware\n')
                        if osDist == 'SLES':
                            (errorMessage, addOnSoftwareInstalled) = installSLESAddOnSoftware(programParentDir, cursesThread)
                        else:
                            (errorMessage, addOnSoftwareInstalled) = installRHELAddOnSoftware(programParentDir, cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('The additional RPMs were not installed, since an attempt to add them was already made.')
                else:
                    addOnSoftwareInstalled = True
                    logger.info('There were no additional RPMs present for the post-upgrade.')
                if 'setTimezone' not in progressDict:
                    f.write('setTimezone\n')
                    errorMessage = setTimezone(programParentDir, cursesThread)
                    if len(errorMessage) > 0:
                        errorMessageList.append(errorMessage)
                    
                else:
                    errorMessageList.append('The time zone was not set, since an attempt to set it was already made.')
                if 'checkNetworkConfiguration' not in progressDict:
                    if 'osRestorationArchiveExtracted' in progressDict or osRestorationArchiveExtracted:
                        f.write('checkNetworkConfiguration\n')
                        if (serverModel == 'ProLiant DL320e Gen8 v2' or serverModel == 'ProLiant DL360 Gen9') and osDistLevel == '11.4':
                            errorMessage = checkNetworkConfiguration(programParentDir, osDist, cursesThread, osDistLevel = osDistLevel)
                        else:
                            errorMessage = checkNetworkConfiguration(programParentDir, osDist, cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('The network configuration was not checked; either because it was already checked or the OS restoration archive was not successfully extracted.')
                if not (serverModel == 'ProLiant DL320e Gen8 v2' or serverModel == 'ProLiant DL360 Gen9') and osDistLevel == '11.4':
                    if 'setHostname' not in progressDict:
                        f.write('setHostname\n')
                        errorMessage = setHostname(programParentDir, cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('The host name was not set, since an attempt to set it was already made.')
                if osDist == 'SLES':
                    if 'updateNTPConf' not in progressDict:
                        f.write('updateNTPConf\n')
                        errorMessage = updateNTPConf(cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('The ntp configuration was not updated, since an attempt to update it was already made.')
                    if 'configureSnapper' not in progressDict:
                        f.write('configureSnapper\n')
                        errorMessage = configureSnapper(osDistLevel, cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('The snapper configuration was not updated, since an attempt to update it was already made.')
                if serverModel != 'Superdome':
                    if 'updateMultipathConf' not in progressDict:
                        f.write('updateMultipathConf\n')
                        errorMessage = updateMultipathConf(cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('The multipath blacklist configuration was not updated, since an attempt to update it was already made.')
                if 'DL580' in serverModel or serverModel == 'Superdome':
                    if 'DL580' in serverModel:
                        if 'updateBIOS' not in progressDict and addOnSoftwareInstalled:
                            f.write('updateBIOS\n')
                            errorMessage = updateBIOS(programParentDir, cursesThread)
                            if len(errorMessage) > 0:
                                errorMessageList.append(errorMessage)
                            
                        else:
                            errorMessageList.append('The BIOS was not updated; either because it was already updated or the additional RPMs failed to install.')
                        if os.path.isdir(programParentDir + '/addOnFileArchive'):
                            if 'installAddOnFiles' not in progressDict:
                                f.write('installAddOnFiles\n')
                                errorMessage = installAddOnFiles(programParentDir, upgradeResourceDict.copy(), osDist, cursesThread, processor = processor)
                                if len(errorMessage) > 0:
                                    errorMessageList.append(errorMessage)
                                
                            else:
                                errorMessageList.append('The files from the add on files archive were not installed, since an attempt to add them was already made.')
                        
                    if serverModel == 'Superdome':
                        if os.path.isdir(programParentDir + '/addOnFileArchive'):
                            if 'installAddOnFiles' not in progressDict:
                                f.write('installAddOnFiles\n')
                                errorMessage = installAddOnFiles(programParentDir, upgradeResourceDict.copy(), osDist, cursesThread, serverModel = serverModel)
                                if len(errorMessage) > 0:
                                    errorMessageList.append(errorMessage)
                                
                            else:
                                errorMessageList.append('The files from the add on files archive were not installed, since an attempt to add them was already made.')
                        if osDist == 'SLES':
                            if 'updateKdump' not in progressDict:
                                f.write('updateKdump\n')
                                errorMessage = updateKdump(cursesThread)
                                if len(errorMessage) > 0:
                                    errorMessageList.append(errorMessage)
                                
                            else:
                                errorMessageList.append('The update of kdump.service to address bug 1008170 was not performed, since an attempt to update the service was already made.')
                        
                    if 'restoreHANAUserAccounts' not in progressDict:
                        f.write('restoreHANAUserAccounts\n')
                        errorMessage = restoreHANAUserAccounts(programParentDir, cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('The SAP HANA user account data was not restored, since an attempt to restore the account data was already made.')
                    if 'restoreHANAPartitionData' not in progressDict:
                        f.write('restoreHANAPartitionData\n')
                        (errorMessage, hanaPartitionsRestored) = restoreHANAPartitionData(programParentDir, cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('The SAP HANA parition data was not restored, since an attempt to restore the data was already made.')
                    if 'sapRestorationArchiveExtracted' not in progressDict and hanaPartitionsRestored:
                        f.write('sapRestorationArchiveExtracted\n')
                        errorMessage = extractSAPRestorationArchive(programParentDir, osDist, cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('The SAP restoration archive was not extracted; either because it was already extracted or the SAP HANA partition data was not successfully restored.')
                    if not scaleUpSystem:
                        if 'prepareSAPHanaDirs' not in progressDict:
                            f.write('prepareSAPHanaDirs\n')
                            errorMessage = prepareSAPHanaDirs(programParentDir, cursesThread)
                            if len(errorMessage) > 0:
                                errorMessageList.append(errorMessage)
                            
                        else:
                            errorMessageList.append('The /hana/data/SID and /hana/log/SID directories were not created; since an attempt to create them was already made.')
                    
                if 'DL380p' in serverModel or 'DL360p' in serverModel:
                    if 'configureXinetd' not in progressDict:
                        f.write('configureXinetd\n')
                        errorMessage = configureXinetd(cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('xinetd was not configured; since an attempt to configure it was already made.')
                    if 'updateLvmConf' not in progressDict:
                        f.write('updateLvmConf\n')
                        errorMessage = updateLvmConf(cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('/etc/lvm.conf was not updated; since an attempt to enable it was already made.')
                    if 'updateNFSListeners' not in progressDict:
                        f.write('updateNFSListeners\n')
                        errorMessage = updateNFSListeners(cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append("The number of NFS listeners in '/opt/cmcluster/nfstoolkit/hananfs.sh' was not updated; since an attempt to update the number was already made.")
                    if 'createNFSMountPoint' not in progressDict:
                        f.write('createNFSMountPoint\n')
                        errorMessage = createNFSMountPoint(cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('The hananfs mount point was not created; since an attempt to create it was already made.')
                    if 'buildDeadmanDriver' not in progressDict:
                        f.write('buildDeadmanDriver\n')
                        errorMessage = buildDeadmanDriver(cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('The deadman driver was not built and installed; since an attempt to build and install it was already made.')
                if serverModel == 'ProLiant DL320e Gen8 v2' or serverModel == 'ProLiant DL360 Gen9':
                    if 'configureServiceguardQS' not in progressDict:
                        f.write('configureServiceguardQS\n')
                        errorMessage = configureServiceguardQS(programParentDir, osDistLevel, cursesThread)
                        if len(errorMessage) > 0:
                            errorMessageList.append(errorMessage)
                        
                    else:
                        errorMessageList.append('Serviceguard QS was not configured; since an attempt to configure it was already made.')
            except IOError:
                err = None
                logger.error('Could not access ' + progressStatusFile + '.\n' + str(err))
                displayErrorMessage("Could not access '" + progressStatusFile + "'; fix the problem and try again.", cursesThread)

            f.close()
            if len(errorMessageList) > 0:
                cursesThread.insertMessage([
                    'warning',
                    "Restoration of the server's configuration has completed with the errors shown below; check the log file for additional information before continuing with the re-installation process:"])
                cursesThread.insertMessage([
                    'warning',
                    ''])
                for message in errorMessageList:
                    cursesThread.insertMessage([
                        'warning',
                        message])
                    cursesThread.insertMessage([
                        'warning',
                        ''])
                
            else:
                cursesThread.insertMessage([
                    'informative',
                    "Restoration of the server's configuration has completed; continue with the next step in the re-installation process."])
                cursesThread.insertMessage([
                    'informative',
                    ''])
            cursesThread.getUserInput([
                'informative',
                'Press enter to exit the program.'])
            cursesThread.insertMessage([
                'informative',
                ''])
            while not cursesThread.isUserInputReady():
                time.sleep(0.1)
            exit(0)
        except Exception:
            err = None
            cursesThread.join()
            logger.error('An unexpected error was encountered:\n' + traceback.format_exc())
            print RED + "An unexpected error was encountered; collect the application's log file and report the error back to the SAP HANA CoE DevOps team." + RESETCOLORS
            print RED + 'Error: ' + str(err) + RESETCOLORS
            exit(1)
        finally:
            cursesThread.join()
예제 #3
0
def main():
	programVersion = '2017.05-rc1'
	hpeUtilitySoftwareInstalled = False

	'''
	The errorMessageList keeps track of errors encountered during the restoration process so that 
	one knows what will have to be done manually if necessary.
	'''
	errorMessageList = []

        #The program can only be ran by root.
        if os.geteuid() != 0:
                print(RED + 'You must be root to run this program; exiting program execution.' + RESETCOLORS)
                exit(1)

	#Change into directory containing the program, which should be the mount point of the ISO image containing the files needed for the post upgrade configuration/update.
	try:
		programParentDir = ''

		cwd = os.getcwd()

		programParentDir = os.path.dirname(os.path.realpath(__file__))

		if cwd != programParentDir:
			os.chdir(programParentDir)
	except OSError as err:
		print(RED + 'Unable to change into the programs parent directory \'' + programParentDir + '\'; fix the problem and try again; exiting program execution.\n' + str(err) + RESETCOLORS)
		exit(1)

        #Get the server's OS distribution version information.
        command = 'cat /proc/version'
        result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        out, err = result.communicate()

        if result.returncode != 0:
                print(RED + 'Unable to get the server\'s OS distribution information; fix the problem and try again; exiting program execution.\n' + err + '\n' + out + RESETCOLORS)
                exit(1)

        #Change version information to lowercase before checking for OS type.
        versionInfo = out.lower()

        if not 'suse' in versionInfo:
                print(RED + 'The OS distribution \'' + versionInfo + '\' is not supported; fix the problem and try again; exiting program execution.' + RESETCOLORS)
                exit(1)

	#Set and create the upgrade working directory if it does not exist.
        upgradeLogDir = '/var/log/CoE_SAP_HANA_SLES_Upgrade_Log_Dir'

	if not os.path.isdir(upgradeLogDir):
		try:
			os.mkdir(upgradeLogDir)
		except OSError as err:
			print(RED + 'Unable to create the post upgrade log directory \'' + upgradeLogDir + '\'; fix the problem and try again; exiting program execution.\n' + str(err) + RESETCOLORS)
			exit(1)

        #Configure logging.
        dateTimestamp = (datetime.datetime.now()).strftime('%d%H%M%b%Y')

        logFile = upgradeLogDir + '/SLES_Post_Upgrade_' + dateTimestamp + '.log'

        handler = logging.FileHandler(logFile)

        logger = logging.getLogger('coeOSUpgradeLogger')

        logger.setLevel(logging.INFO)

        formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(message)s', datefmt='%m/%d/%Y %H:%M:%S')
        handler.setFormatter(formatter)
        logger.addHandler(handler)

	logger.info('The current version of the program is: ' + programVersion + '.')

	#Only Ivy Bridge and Haswell systems are supported for an upgrade.
	processorDict = {'62' : 'ivybridge', '63' : 'haswell'}

        command = 'cat /proc/cpuinfo'
        result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        out, err = result.communicate()

        if result.returncode != 0:
                logger.error('There was a problem getting the cpu information.\n' + err + '\n' + out)
                print(RED + 'There was a problem getting the cpu information; fix the problem and try again; exiting program execution.' + RESETCOLORS)
                exit(1)

	cpudata = out.splitlines()

	for line in cpudata:
		if re.match('\s*model\s+:\s+[2-9]{2}', line) != None:
			try:
				processor = processorDict[re.match('\s*model\s+:\s+([2-9]{2})', line).group(1)]
			except AttributeError as err:
				logger.error('There was a match error when trying to match against ' + line + '.\n' + str(err))
				print(RED + 'There was a match error matching against \'' + line + '\'; fix the problem and try again; exiting program execution.' + RESETCOLORS)
				exit(1)
			except KeyError as err:
				logger.error('The resource key (' + str(err) + ') was not present in the processor dictionary.')
				print(RED + 'The server is not supported for an upgrade, since it is not using a Haswell or Ivy Bridge processor; fix the problem and try again; exiting program execution.' + RESETCOLORS)
				exit(1)
			
			break

        #This dictionary holds the resource files resources.
        upgradeResourceDict = {}

        #Get the upgrade resource file data and save it to a dictionary (hash).
        try:
                with open('upgradeResourceFile') as f:
                        for line in f:
                                line = line.strip()

                                #Ignore commented and blank lines.
                                if len(line) == 0 or re.match("^\s*#", line) or re.match('^\s+$', line):
                                        continue
                                else:
                                        #Remove quotes from resources.
                                        line = re.sub('[\'"]', '', line)

                                        (key, val) = line.split('=')
                                        key = key.strip()
                                        upgradeResourceDict[key] = re.sub('\s+', '', val)
        except IOError as err:
                logger.error('Unable to access the application\'s resource file \'upgradeResourceFile\'.\n' + str(err))
                print(RED + 'Unable to access the application\'s resource file \'upgradeResourceFile\'; fix the problem and try again; exiting program execution.' + RESETCOLORS)
                exit(1)

	#Setup curses, so that messages can be scrolled during program execution.
        sessionScreenLog = upgradeLogDir + '/sessionScreenLog.log'
        cursesLog = upgradeLogDir + '/cursesLog.log'

        try:
                '''
                The application uses curses to manage the display so that we have two
                windows. One for feedback and one for conversing.  Also, scrolling is implemented.
                '''
                cursesThread = CursesThread(sessionScreenLog, cursesLog)
                cursesThread.daemon = True
                cursesThread.start()

		'''
		Check to make sure the restoration archive file from the preupgrade is not corrupt.
		Three attempts will be made before using the restoration archive is abandoned.
		'''
		restorationArchiveErrorFile = upgradeLogDir + '/.restorationArchiveError'

		if not os.path.isfile(restorationArchiveErrorFile):
			try:
				os.mknod(restorationArchiveErrorFile)
			except OSError as err:
				logger.error('Unable to create the restoration archive error file \'' + restorationArchiveErrorFile + '\'.\n' + str(err))
				displayErrorMessage('Unable to create the restoration archive error file \'' + restorationArchiveErrorFile + '\'; fix the problem and try again.', cursesThread)

		'''
		The progress status file is used to keep track of what was already done in case the 
		program is ran again. Thus, only those functions that were note already ran will be run.
		'''
		progressStatusFile = upgradeLogDir + '/.restorationProgress'

		try:
			if os.path.isfile(progressStatusFile):
				with open(progressStatusFile) as f:
					progressDict = dict.fromkeys(x.strip() for x in f)
			else:
				progressDict = {}

			if os.path.isfile(progressStatusFile):
				f = open(progressStatusFile, 'a')
			else:
				f = open(progressStatusFile, 'w')

			'''	
			This variable is used to identify if the restoration archive was successfully extracted,
			since it may not be in the progress status file yet, while attempts to extract the archive
			are still being made.
			'''
			restorationArchiveExtracted = False

			try:
				#Check and extract the restoration archive; three attempts are allowed.
				if os.stat(restorationArchiveErrorFile).st_size < 50 and not 'restorationArchiveExtracted' in progressDict:
					cursesThread.insertMessage(['informative', 'Checking and extracting the restoration archive file.'])
					cursesThread.insertMessage(['informative', ''])
					preUpgradeArchive = checkPreupgradeArchive(programParentDir, restorationArchiveErrorFile, cursesThread)
					if extractPreupgradeArchive(preUpgradeArchive, restorationArchiveErrorFile, cursesThread):
						f.write('restorationArchiveExtracted\n')
						restorationArchiveExtracted = True
			except OSError as err:
				logger.error('Unable to access the restoration archive error file \'' + restorationArchiveErrorFile + '\'.\n' + str(err))
				displayErrorMessage('Unable to access the restoration archive error file \'' + restorationArchiveErrorFile + '\'; fix the problem and try again.', cursesThread)

			if not 'setHostname' in progressDict:
				f.write('setHostname\n')

				errorMessage = setHostname(programParentDir, cursesThread)
			
				if len(errorMessage) > 0:
					errorMessageList.append(errorMessage)

			if not 'installHPEUtilitySoftware' in progressDict:
				f.write('installHPEUtilitySoftware\n')

				(errorMessage, hpeUtilitySoftwareInstalled)  = installHPEUtilitySoftware(programParentDir, cursesThread)
			
				if len(errorMessage) > 0:
					errorMessageList.append(errorMessage)

			if not 'updateBIOS' in progressDict and hpeUtilitySoftwareInstalled:
				f.write('updateBIOS\n')
				errorMessage = updateBIOS(programParentDir, cursesThread)
			
				if len(errorMessage) > 0:
					errorMessageList.append(errorMessage)

			if not 'updateOSSettings' in progressDict:
				f.write('updateOSSettings\n')
				osErrorMessageList = updateOSSettings(cursesThread)
			
				if len(osErrorMessageList) > 0:
					errorMessageList += osErrorMessageList

			if not 'installAddOnFiles' in progressDict:
				f.write('installAddOnFiles\n')
				errorMessage = installAddOnFiles(programParentDir, processor, cursesThread)

				if len(errorMessage) > 0:
					errorMessageList.append(errorMessage)

			if not 'checkNetworkConfiguration' in progressDict and ('restorationArchiveExtracted' in progressDict or restorationArchiveExtracted):
				f.write('checkNetworkConfiguration\n')
				errorMessage = checkNetworkConfiguration(programParentDir, cursesThread)

				if len(errorMessage) > 0:
					errorMessageList.append(errorMessage)

			if not 'restoreHANAUserAccounts' in progressDict:
				f.write('restoreHANAUserAccounts\n')
				errorMessage = restoreHANAUserAccounts(programParentDir, cursesThread)

				if len(errorMessage) > 0:
					errorMessageList.append(errorMessage)

			if not 'restoreHANAPartitionData' in progressDict:
				f.write('restoreHANAPartitionData\n')
				errorMessage = restoreHANAPartitionData(programParentDir, cursesThread)

				if len(errorMessage) > 0:
					errorMessageList.append(errorMessage)
		except IOError as err:
			logger.error('Could not access ' + progressStatusFile + '.\n' + str(err))
			displayErrorMessage('Could not access \'' + progressStatusFile + '\'; fix the problem and try again.', cursesThread)

		f.close()

		if len(errorMessageList) > 0:
			cursesThread.insertMessage(['warning', 'Restoration of the server has completed with the errors shown below; check the log file for additional information:'])
			cursesThread.insertMessage(['warning', ''])

			for message in errorMessageList:
				cursesThread.insertMessage(['warning', message])
				cursesThread.insertMessage(['warning', ''])
		else:
			cursesThread.insertMessage(['informative', 'Restoration of the server has completed; check log files and perform a functional check before turning the server back over to the customer.'])
			cursesThread.insertMessage(['informative', ''])
	
		cursesThread.getUserInput(['informative', 'Press enter to exit the program.'])
		cursesThread.insertMessage(['informative', ''])

		while not cursesThread.isUserInputReady():
			time.sleep(0.1)
		exit(0)

        except Exception:
                cursesThread.join()
                traceback.print_exc()
                exit(1)
        finally:
                cursesThread.join()
예제 #4
0
def main():
    if os.geteuid() != 0:
        print RED + 'You must be root to run this program; exiting program execution.' + RESETCOLORS
        exit(1)
    programVersion = '1.0-0'
    usage = 'usage: %prog [[-d] [-h] [-v]]'
    parser = optparse.OptionParser(usage=usage)
    parser.add_option(
        '-d',
        action='store_true',
        default=False,
        help=
        'This option is used when problems are encountered and additional debug information is needed.'
    )
    parser.add_option(
        '-v',
        action='store_true',
        default=False,
        help="This option is used to display the application's version.")
    options, args = parser.parse_args()
    if options.v:
        print os.path.basename(sys.argv[0]) + ' ' + programVersion
        exit(0)
    if options.d:
        debug = True
    else:
        debug = False
    versionInformationLogOnly = True
    updateOSHarddrives = False
    healthBasePath = '/hp/support/health'
    currentLogDir = datetime.datetime.now().strftime(
        'Date_%d%b%Y_Time_%H:%M:%S')
    logBaseDir = healthBasePath + '/log/' + currentLogDir + '/'
    sessionScreenLog = logBaseDir + 'sessionScreenLog.log'
    cursesLog = logBaseDir + 'cursesLog.log'
    try:
        os.mkdir(logBaseDir)
    except OSError as err:
        print RED + 'Unable to create the current log directory ' + logBaseDir + '; fix the problem and try again; exiting program execution.\n' + str(
            err) + RESETCOLORS
        exit(1)

    try:
        cursesThread = CursesThread(sessionScreenLog, cursesLog)
        cursesThread.daemon = True
        cursesThread.start()
        initialize = Initialize(cursesThread)
        healthResourceDict = initialize.init(healthBasePath, logBaseDir, debug,
                                             programVersion,
                                             versionInformationLogOnly,
                                             updateOSHarddrives)
        cursesThread.insertMessage([
            'informative',
            'The Health Check report has been created and is in the ' +
            healthBasePath + ' directory.'
        ])
        cursesThread.insertMessage(['info', ' '])
        cursesThread.getUserInput(['informative', 'Press enter to exit.'])
        while not cursesThread.isUserInputReady():
            time.sleep(0.1)

    except Exception:
        cursesThread.join()
        traceback.print_exc()
        exit(1)
    finally:
        cursesThread.join()
        versionInformationLog = logBaseDir + 'HealthCheckReport.txt'
        if os.path.isfile(versionInformationLog):
            try:
                with open(versionInformationLog) as f:
                    for line in f:
                        print line.strip()

                    print '\n'
            except IOError as err:
                print 'I/O Error while trying to print ' + versionInformationLog + '.\n' + err + '\n'
예제 #5
0
def main():
    if os.geteuid() != 0:
        print(
            RED +
            "You must be root to run this program; exiting program execution."
            + RESETCOLORS)
        exit(1)

    programVersion = '1.2-rc1'

    #Parse options before setting up curses mode.
    usage = 'usage: %prog [[-h] [-r] [-u] [-v]]'

    parser = optparse.OptionParser(usage=usage)

    parser.add_option('-r',
                      action='store_true',
                      default=False,
                      help='This option is used to generate a version report.')
    parser.add_option(
        '-u',
        action='store_true',
        default=False,
        help=
        'This option is used to update the local OS hard drives before the mirror is split.'
    )
    parser.add_option(
        '-v',
        action='store_true',
        default=False,
        help='This option is used to display the application\'s version.')

    (options, args) = parser.parse_args()

    if options.v:
        print(os.path.basename(sys.argv[0]) + ' ' + programVersion)
        exit(0)

    count = 0

    for option in options:
        if options[option]:
            count += 1

    if count > 1:
        print(
            RED +
            "Options are mutually exclusive; please try again; exiting program execution."
            + RESETCOLORS)
        exit(1)

    if options.r:
        versionInformationLogOnly = True
    else:
        versionInformationLogOnly = False

    if options.u:
        updateOSHarddrives = True
    else:
        updateOSHarddrives = False

    #This is the location of the csur application.
    csurBasePath = '/hp/support/csur'
    '''
	These log files have their name hardcoded, since their logging starts before the
	csur application's resource file is read.
	'''
    currentLogDir = datetime.datetime.now().strftime(
        "Date_%d%b%Y_Time_%H:%M:%S")
    logBaseDir = csurBasePath + '/log/' + currentLogDir + '/'
    sessionScreenLog = logBaseDir + 'sessionScreenLog.log'
    cursesLog = logBaseDir + 'cursesLog.log'

    try:
        os.mkdir(logBaseDir)
    except OSError as err:
        print(RED + 'Unable to create the current log directory ' +
              logBaseDir +
              '; fix the problem and try again; exiting program execution.\n' +
              str(err) + RESETCOLORS)
        exit(1)

    try:
        '''
		The application uses curses to manage the display so that we have two 
		windows. One for feedback and one for conversing.  Also, scrolling is implemented.
		'''
        cursesThread = CursesThread(sessionScreenLog, cursesLog)
        cursesThread.daemon = True
        cursesThread.start()

        initialize = Initialize(cursesThread)

        csurResourceDict = initialize.init(csurBasePath, logBaseDir,
                                           programVersion,
                                           versionInformationLogOnly,
                                           updateOSHarddrives)

        if options.r:
            cursesThread.insertMessage([
                'informative',
                'The system version report has been created and is in the log directory.'
            ])
            cursesThread.insertMessage(['info', ' '])
        else:
            #The computeNodeList will be empty if the node did not need to be updated.
            if len(csurResourceDict['componentListDict']
                   ['computeNodeList']) == 0:
                cursesThread.insertMessage([
                    'informative',
                    'The compute node is already up to date; no action taken.'
                ])
            else:
                '''
				For a Scale-up system/Compute Nodes only there will only be two timer threads.  One for the initial initialization 
				and a second for the update.			
				'''
                timerThreadLocation = 1

                computeNodeDict = csurResourceDict['componentListDict'][
                    'computeNodeList'][0].getComputeNodeDict()
                hostname = computeNodeDict['hostname']

                if updateOSHarddrives:
                    cursesThread.insertMessage([
                        'informative', "Phase 2: Updating compute node " +
                        hostname + "'s hard drives that need to be updated."
                    ])
                else:
                    cursesThread.insertMessage([
                        'informative', "Phase 2: Updating the compute node " +
                        hostname + "'s components that need to be updated."
                    ])

                #Instantiate the computeNode update class, which will do the work of updating the compute node.
                computeNodeUpdate = ComputeNodeUpdate(cursesThread,
                                                      csurResourceDict.copy(),
                                                      timerThreadLocation)

                #Get the current signal handlers so that they can be restored after the update is completed.
                original_sigint_handler = signal.getsignal(signal.SIGINT)
                original_sigquit_handler = signal.getsignal(signal.SIGQUIT)
                '''
				Setup signal handler to intercept SIGINT and SIGQUIT.
				'''

                s = SignalHandler(cursesThread)

                signal.signal(signal.SIGINT, s.signal_handler)
                signal.signal(signal.SIGQUIT, s.signal_handler)

                #Create and start the worker thread.
                workerThread = Thread(
                    target=computeNodeUpdate.updateComputeNodeComponents)
                workerThread.start()

                #Wait for the thread to either stop or get interrupted.
                while 1:
                    time.sleep(0.1)

                    if not workerThread.is_alive():
                        break
                    '''
					The response will be an empty string unless a signal was received.  If a signal is
					received then response is either 'n' (Don't cancel the update) or 'y' (Cancel the update.).
					'''
                    response = s.getResponse()

                    if response != '':
                        if response == 'y':
                            computeNodeUpdate.endTask()
                            cursesThread.join()
                            exit(1)

                #Restore the original signal handlers.
                signal.signal(signal.SIGINT, original_sigint_handler)
                signal.signal(signal.SIGQUIT, original_sigquit_handler)

                componentProblemDict = computeNodeUpdate.getUpdateComponentProblemDict(
                )

                #Update the CSUR version information file.
                if not updateOSHarddrives:
                    updateVersionInformationFileResult = updateVersionInformationFile(
                        csurResourceDict.copy())

                #Move cursor down for formatting purposes.
                cursesThread.insertMessage(['info', ' '])

                if len(componentProblemDict['Software']) == 0 and len(
                        componentProblemDict['Drivers']) == 0 and len(
                            componentProblemDict['Firmware']) == 0:
                    if not updateOSHarddrives:
                        if not updateVersionInformationFileResult:
                            cursesThread.insertMessage([
                                'warning',
                                'The update of compute node ' + hostname +
                                ' completed succesfully, however, the version information file update failed; check the log file for errors and update the file manually.'
                            ])
                            cursesThread.insertMessage(['info', ' '])
                            if computeNodeDict['externalStoragePresent']:
                                cursesThread.insertMessage([
                                    'final',
                                    'Once the version information file is updated, power cycle the attached storage controller(s) and reboot the system for the changes to take effect.'
                                ])
                            else:
                                cursesThread.insertMessage([
                                    'final',
                                    'Once the version information file is updated, reboot the system for the changes to take effect.'
                                ])
                        else:
                            cursesThread.insertMessage([
                                'informative', 'The update of compute node ' +
                                hostname + ' completed succesfully.'
                            ])
                            cursesThread.insertMessage(['info', ' '])
                            if computeNodeDict['externalStoragePresent']:
                                cursesThread.insertMessage([
                                    'final',
                                    'Power cycle the attached storage controller(s) and reboot the system for the changes to take effect.'
                                ])
                            else:
                                cursesThread.insertMessage([
                                    'final',
                                    'Reboot the system for the changes to take effect.'
                                ])
                    else:
                        cursesThread.insertMessage([
                            'informative', 'The update of compute node ' +
                            hostname + ' completed succesfully.'
                        ])
                        cursesThread.insertMessage(['info', ' '])
                        cursesThread.insertMessage([
                            'final',
                            'Reboot the system for the changes to take effect.'
                        ])
                else:
                    if not updateOSHarddrives:
                        errorMessage = 'The following components encountered errors during the update of compute node ' + hostname + '; check the log file for errors:\n'

                        if len(componentProblemDict['Software']) != 0:
                            '''
							Print the keys which are the names of the software package(s) that had issues while being installed. Else
							print the names of the software package(s) that had issues while being removed/installed.
							'''
                            if not 'rpmRemovalFailure' in componentProblemDict[
                                    'Software']:
                                errorMessage += 'Software: ' + ', '.join(
                                    componentProblemDict['Software'].keys(
                                    )) + '\n'
                            else:
                                if len(componentProblemDict['Software']) == 1:
                                    errorMessage += 'Software: ' + componentProblemDict[
                                        'Software']['rpmRemovalFailure'] + '\n'
                                else:
                                    errorMessage += 'Software: ' + componentProblemDict[
                                        'Software']['rpmRemovalFailure'] + ', '
                                    del componentProblemDict['Software'][
                                        'rpmRemovalFailure']
                                    errorMessage += ', '.join(
                                        componentProblemDict['Software'].keys(
                                        )) + '\n'

                        if len(componentProblemDict['Drivers']) != 0:
                            errorMessage += 'Drivers: ' + ', '.join(
                                componentProblemDict['Drivers'].keys()) + '\n'

                        if len(componentProblemDict['Firmware']) != 0:
                            errorMessage += 'Firmware: ' + ', '.join(
                                componentProblemDict['Firmware'].keys()) + '\n'

                        if not updateVersionInformationFileResult:
                            errorMessage += 'Also, the version information file update failed; check the log file for errors and update the file manually.'

                        cursesThread.insertMessage(['error', errorMessage])
                    else:
                        cursesThread.insertMessage([
                            'error',
                            "Errors were encountered while updating compute node "
                            + hostname +
                            "'s hard drive firmware; check the log file for errors."
                        ])

        cursesThread.insertMessage(['info', ' '])

        cursesThread.getUserInput(['informative', 'Press enter to exit.'])

        while not cursesThread.isUserInputReady():
            time.sleep(0.1)

    except Exception:
        cursesThread.join()
        traceback.print_exc()
        exit(1)
    finally:
        cursesThread.join()
예제 #6
0
def main():
    if os.geteuid() != 0:
        print(
            RED +
            "You must be root to run this program; exiting program execution."
            + RESETCOLORS)
        exit(1)

    programVersion = '1.0-0'
    #Parse options before setting up curses mode.
    usage = 'usage: %prog [[-d] [-h] [-v]]'

    parser = optparse.OptionParser(usage=usage)

    parser.add_option(
        '-d',
        action='store_true',
        default=False,
        help=
        'This option is used when problems are encountered and additional debug information is needed.'
    )
    parser.add_option(
        '-v',
        action='store_true',
        default=False,
        help='This option is used to display the application\'s version.')

    (options, args) = parser.parse_args()

    if options.v:
        print(os.path.basename(sys.argv[0]) + ' ' + programVersion)
        exit(0)

    if options.d:
        debug = True
    else:
        debug = False

    #This is the location of the application.
    csurBasePath = '/hp/support/csur'
    '''
	These log files have their name hardcoded, since their logging starts before the
	application's resource file is read.
	'''
    logBaseDir = csurBasePath + '/log/'
    sessionScreenLog = logBaseDir + 'sessionScreenLog.log'
    cursesLog = logBaseDir + 'cursesLog.log'

    #Always start with an empty log directory when performing a new update.
    try:
        logList = os.listdir(logBaseDir)

        for log in logList:
            os.remove(logBaseDir + log)
    except OSError as err:
        print(RED + 'Unable to remove old logs in ' + logBaseDir +
              '; fix the problem and try again; exiting program execution.\n' +
              str(err) + RESETCOLORS)
        exit(1)

    try:
        '''
		The application uses curses to manage the display so that we have two 
		windows. One for feedback and one for conversing.  Also, scrolling is implemented.
		'''
        cursesThread = CursesThread(sessionScreenLog, cursesLog)
        cursesThread.daemon = True
        cursesThread.start()

        initialize = Initialize(cursesThread)

        csurResourceDict = initialize.init(csurBasePath, debug, programVersion)

        if 'Scale-up' in csurResourceDict['systemType']:
            #The computeNodeList will be empty if the node did not need to be updated.
            if len(csurResourceDict['componentListDict']
                   ['computeNodeList']) == 0:
                cursesThread.insertMessage([
                    'informative',
                    'The compute node is already up to date; no action taken.'
                ])
            else:
                '''
				For a Scale-up system there will only be two timer threads.  One for the initial initialization 
				and a second for the update.			
				'''
                timerThreadLocation = 1

                computeNodeDict = csurResourceDict['componentListDict'][
                    'computeNodeList'][0].getComputeNodeDict()

                cursesThread.insertMessage([
                    'informative',
                    'Phase 2: Updating the compute node components that need to be updated.'
                ])

                #Instantiate the computeNode update class, which will do the work of updating the compute node.
                computeNodeUpdate = ComputeNodeUpdate(cursesThread,
                                                      csurResourceDict.copy(),
                                                      timerThreadLocation)

                #Get the current signal handlers so that they can be restored after the update is completed.
                original_sigint_handler = signal.getsignal(signal.SIGINT)
                original_sigquit_handler = signal.getsignal(signal.SIGQUIT)
                '''
				Setup signal handler to intercept SIGINT and SIGQUIT.
				'''

                s = SignalHandler(cursesThread)

                signal.signal(signal.SIGINT, s.signal_handler)
                signal.signal(signal.SIGQUIT, s.signal_handler)

                #Create and start the worker thread.
                workerThread = Thread(
                    target=computeNodeUpdate.updateComputeNodeComponents)
                workerThread.start()

                #Wait for the thread to either stop or get interrupted.
                while 1:
                    time.sleep(0.1)

                    if not workerThread.is_alive():
                        break
                    '''
					The response will be an empty string unless a signal was received.  If a signal is
					received then response is either 'n' (Don't cancel the update) or 'y' (Cancel the update.).
					'''
                    response = s.getResponse()

                    if response != '':
                        if response == 'y':
                            computeNodeUpdate.endTask()
                            cursesThread.join()
                            exit(1)

                #Restore the original signal handlers.
                signal.signal(signal.SIGINT, original_sigint_handler)
                signal.signal(signal.SIGQUIT, original_sigquit_handler)

                componentProblemDict = computeNodeUpdate.getUpdateComponentProblemDict(
                )

                #Update the CSUR version information file.
                updateVersionInformationFileResult = updateVersionInformationFile(
                    csurResourceDict.copy())

                #Move cursor down for formatting purposes.
                cursesThread.insertMessage(['info', ' '])

                if len(componentProblemDict['Software']) == 0 and len(
                        componentProblemDict['Drivers']) == 0 and len(
                            componentProblemDict['Firmware']) == 0:
                    if not updateVersionInformationFileResult:
                        cursesThread.insertMessage([
                            'warning',
                            'The compute node update completed succesfully, however, the version information file update failed; check the log file for errors and update the file manually.'
                        ])
                        cursesThread.insertMessage(['info', ' '])
                        if computeNodeDict['externalStoragePresent']:
                            cursesThread.insertMessage([
                                'final',
                                'Once the version information file is updated, power cycle the attached storage controller(s) and reboot the system for the changes to take effect.'
                            ])
                        else:
                            cursesThread.insertMessage([
                                'final',
                                'Once the version information file is updated, reboot the system for the changes to take effect.'
                            ])
                    else:
                        cursesThread.insertMessage([
                            'informative',
                            'The compute node update completed succesfully.'
                        ])
                        cursesThread.insertMessage(['info', ' '])
                        if computeNodeDict['externalStoragePresent']:
                            cursesThread.insertMessage([
                                'final',
                                'Power cycle the attached storage controller(s) and reboot the system for the changes to take effect.'
                            ])
                        else:
                            cursesThread.insertMessage([
                                'final',
                                'Reboot the system for the changes to take effect.'
                            ])
                else:
                    errorMessage = 'The following components encountered errors during the update; check the log file for errors:\n'

                    if len(componentProblemDict['Software']) != 0:
                        errorMessage += 'Software: ' + ', '.join(
                            componentProblemDict['Software'].keys()) + '\n'

                    if len(componentProblemDict['Drivers']) != 0:
                        errorMessage += 'Drivers: ' + ', '.join(
                            componentProblemDict['Drivers'].keys()) + '\n'

                    if len(componentProblemDict['Firmware']) != 0:
                        errorMessage += 'Firmware: ' + ', '.join(
                            componentProblemDict['Firmware'].keys()) + '\n'

                    if not updateVersionInformationFileResult:
                        errorMessage += 'Also, the version information file update failed; check the log file for errors and update the file manually.'

                    cursesThread.insertMessage(['error', errorMessage])
        else:
            pass

        cursesThread.insertMessage(['info', ' '])

        cursesThread.getUserInput(['informative', 'Press enter to exit.'])

        while not cursesThread.isUserInputReady():
            time.sleep(0.1)

    except Exception:
        cursesThread.join()
        traceback.print_exc()
        exit(1)
    finally:
        cursesThread.join()