Edit file File name : check_smartarray.py Content :#!/usr/bin/python # -*- coding:utf-8 -*- #### # # NAME: check_smartarray.py # # AUTHOR: Christophe Robert - christophe °dot° robert °at° cocoche °dot° fr # # DESC: Check HP SmartArray RAID status on Linux - hpacucli/hpssacli/ssacli command line tool # # Script compatibility : Python 2+ # Return Values : # No problems - OK (exit code 0) # Drive status != OK but not "Failed" - WARNING (exit code 1) # Drive status is "Failed" - CRITICAL (exit code 2) # # TODO : Script errors - UNKNOWN (exit code 3) # # VERSION: 1.0 - Initial dev. - 09-02-2012 (02 Sept. 2012) # 1.1 - Correcting some errors and add comments - 09-15-2013 (15 Sept. 2013) # * Add SAS array to be considerated (only SATA was before) # * Add comments # * Add UNKNOWN mark - script errors # 1.2 - Correcting some errors - 09-24-2013 (24 Sept. 2013) # * Add SCSI array to be considerated # * Add comments # 1.3 - Modify script from Windows PowerShell command tool to Python one's - 01-07-2015 (07 Jan. 2015) # 1.4 - Add controller, battery and cache status checks - 01-08-2015 (08 Jan. 2015) # 1.5 - Modify result analisys - 01-12-2015 (12 Jan. 2015) # 1.6 - Support for `hpacucli`, `hpssacli` and `ssacli` - 2018-02-22 (22. Feb. 2018) # #### import os import sys import re from subprocess import * import logging import logging.handlers class ReadHPSmartArrayStatus: def __init__(self, tuple, logger): self.nagios = tuple self.logger = logger #creation de table de hash qui permet d'associer une clé et une valeur self.system = {'ctrl': [], 'array': [], 'logical': [], 'physical': []} self.ctrl_nb = 0 self.array_nb = 0 self.lv_nb = 0 self.pd_nb = 0 def process(self): for element in self.nagios: sata = re.compile('^.*[Aa]rray.*SATA.*$') sas = re.compile('^.*[Aa]rray.*SAS.*$') scsi = re.compile('^.*[Aa]rray.*SCSI.*$') smart = re.compile('^Smart Array .*$') logical = re.compile('^.*logicaldrive.*$') physical = re.compile('^.*physicaldrive.*$') # Insert all controllers in dedicated list of dict if (smart.match(element)): self.logger.debug('--Debug-- Enter smart') self.logger.debug('--Debug-- Value = ' + element) self.ctrl_nb += 1 self.system['ctrl'].append(element) self.logger.debug('--Debug-- Dict :' + str(self.system)) # Insert all arrays in dedicated list of dict elif (sata.match(element) or sas.match(element) or scsi.match(element)): self.logger.debug('--Debug-- Enter array') self.logger.debug('--Debug-- Value = ' + element) self.array_nb += 1 self.system['array'].append(element) self.logger.debug('--Debug-- Dict :' + str(self.system)) # Insert all logicaldrives in dedicated list of dict elif (logical.match(element)): self.logger.debug('--Debug-- Enter logical') self.logger.debug('--Debug-- Value = ' + element) # Add the next logical drive to the previous array dict self.lv_nb += 1 self.system['logical'].append(element) self.logger.debug('--Debug-- Dict :' + str(self.system)) # Insert all physicaldives in dedicated list of dict elif (physical.match(element)): self.logger.debug('--Debug-- Enter physical') self.logger.debug('--Debug-- Value = ' + element) # Add the next physical drive to the previous logical drive dict self.pd_nb += 1 self.system['physical'].append(element) self.logger.debug('--Debug-- Dict :' + str(self.system)) self.logger.debug('--Debug-- Show "system" dict content') self.logger.debug('--Debug-- Value = ' + str(self.system)) return self.system class GetErrors: def __init__(self, buffer, logger): self.errors = {'CRITICAL': [], 'WARNING': [], 'UNKNOWN': []} self.tocheck = buffer self.logger = logger self.nb_ctrl = 0 self.nb_array = 0 self.nb_logical = 0 self.nb_physical = 0 def check(self): sata = re.compile('^.*array.*SATA.*$') sas = re.compile('^.*array.*SAS.*$') scsi = re.compile('^.*array.*SCSI.*$') logical = re.compile('^.*logicaldrive.*$') physical = re.compile('^.*physicaldrive.*$') # For each controller found, check errors and find S/N for i in range(len(self.tocheck['ctrl'])): self.logger.debug('--Debug-- Controller : ' + str(self.tocheck['ctrl'][i])) self.nb_ctrl += 1 #self.logger.debug('--Debug-- S/N : ' + self.tocheck['ctrl'][i].split('sn: ')[1].split(')')[0]) self.logger.debug('--Debug-- Slot : ' + self.tocheck['ctrl'][i].split('Slot ')[1].split(' ')[0]) ctrl_status = Popen(['sudo', smartarray_bin, 'ctrl', 'slot=' + self.tocheck['ctrl'][i].split('Slot ')[1].split(' ')[0], 'show', 'status'], stdout=PIPE) res = ctrl_status.communicate()[0] ctrl_status.stdout.close() ctrl = [] for r in res.splitlines(): r = r.lstrip() logger.debug(str(r)) if (r != ''): ctrl.append(r) self.logger.debug('--Debug-- Controller internal status : ' + str(ctrl)) for element in ctrl: if re.compile('.*Status:.*').match(element): self.logger.debug('--Debug-- Controller element status : ' + element) if element.split(': ')[1].split('\n')[0] != 'OK': self.errors['WARNING'].append(element) # For each array found, check errors for i in range(len(self.tocheck['array'])): self.logger.debug('--Debug-- Enter "array"') self.logger.debug('--Debug-- Value = ' + str(self.tocheck['array'][i])) self.nb_array += 1 # For each logicaldrive found, check errors for i in range(len(self.tocheck['logical'])): self.logger.debug('--Debug-- Enter "logicaldrive"') self.logger.debug('--Debug-- Value = ' + str(self.tocheck['logical'][i])) self.nb_logical += 1 if re.compile('^.*OK.*$').match(self.tocheck['logical'][i]): self.logger.debug(re.compile('^.*OK.*$').match(self.tocheck['logical'][i])) pass elif re.compile('^.*Failed.*$').match(self.tocheck['logical'][i]): self.logger.debug(re.compile('^.*Failed.*$').match(self.tocheck['logical'][i])) self.errors['CRITICAL'].append(self.tocheck['logical'][i]) elif re.compile('^.*Recover.*$').match(self.tocheck['logical'][i]): self.logger.debug(re.compile('^.*Recover.*$').match(self.tocheck['logical'][i])) self.errors['WARNING'].append(self.tocheck['logical'][i]) else: self.logger.debug(self.tocheck['logical'][i]) self.errors['UNKNOWN'].append(self.tocheck['logical'][i]) # For each logicaldrive found, check errors for i in range(len(self.tocheck['physical'])): self.logger.debug('--Debug-- Enter "physicaldrive"') self.logger.debug('--Debug-- Value = ' + str(self.tocheck['physical'][i])) self.nb_physical += 1 if re.compile('^.*OK.*$').match(self.tocheck['physical'][i]): self.logger.debug(re.compile('^.*OK.*$').match(self.tocheck['physical'][i])) pass elif re.compile('^.*Failed.*$').match(self.tocheck['physical'][i]): self.logger.debug(re.compile('^.*Failed.*$').match(self.tocheck['physical'][i])) self.errors['CRITICAL'].append(self.tocheck['physical'][i]) elif re.compile('^.*Rebuilding.*$').match(self.tocheck['physical'][i]): self.logger.debug(re.compile('^.*Rebuilding.*$').match(self.tocheck['physical'][i])) self.errors['WARNING'].append(self.tocheck['physical'][i]) else: self.logger.debug(self.tocheck['physical'][i]) self.errors['UNKNOWN'].append(self.tocheck['physical'][i]) self.logger.debug('--Debug-- Errors dict : ' + str(self.errors)) return self.errors, self.nb_ctrl, self.nb_array, self.nb_logical, self.nb_physical ### Core ### logger = logging.getLogger('check_smartarray') logger.setLevel(logging.DEBUG) handler = logging.handlers.SysLogHandler(address='/dev/log') logger.addHandler(handler) # Check which HP SmartArray management utility is installed if os.path.isfile('/usr/sbin/hpacucli'): smartarray_bin = 'hpacucli' elif os.path.isfile('/usr/sbin/hpssacli'): smartarray_bin = 'hpssacli' elif os.path.isfile('/usr/sbin/ssacli'): smartarray_bin = 'ssacli' else: logger.debug('--Debug-- HP SmartArray management utility not found.') sys.exit(2) # Get array status from SmartArray management utility hpacucli = Popen(['sudo', smartarray_bin, 'ctrl', 'all', 'show', 'config'], stdout=PIPE) res = hpacucli.communicate()[0] hpacucli.stdout.close() nagios = [] for r in res.splitlines(): r = r.lstrip() logger.debug(str(r)) if (r != ''): nagios.append(r) logger.debug('--Debug-- List command results :') logger.debug(nagios) nb_warning = 0 nb_critical = 0 nb_unknown = 0 tosend = "" try: # Parse and analyse returned lines state = ReadHPSmartArrayStatus(nagios, logger) config = state.process() # Check errors errors = GetErrors(config, logger) health, nb_ctrl, nb_array, nb_logical, nb_physical = errors.check() logger.debug('--Debug-- Health dict : ' + str(health)) if len(health['CRITICAL']): logger.debug('--Debug-- Enter critical') nb_critical += 1 for l in range(len(health['CRITICAL'])): tosend += 'CRITICAL - ' + health['CRITICAL'][l] + '\n' elif len(health['WARNING']) and nb_critical==0: logger.debug('--Debug-- Enter warning') nb_warning += 1 for l in range(len(health['WARNING'])): tosend += 'WARNING - ' + health['WARNING'][l] + '\n' elif len(health['UNKNOWN']) and nb_critical==0 and nb_warning==0: logger.debug('--Debug-- Enter unknown') nb_unknown += 1 for l in range(len(health['UNKNOWN'])): tosend += 'UNKNOWN - ' + health['UNKNOWN'][l] + '\n' elif nb_ctrl == 0 or nb_array == 0 or nb_logical == 0 or nb_physical == 0: logger.debug('--Debug-- Enter unknown') nb_unknown += 1 tosend += 'UNKNOWN - One of element of these : controller (' + str(nb_ctrl) + '), array (' + str(nb_array) + '), logicaldrive (' + str(nb_logical) + ') or physicaldrive (' +str(nb_physical) + ') is missing !\n' else: tosend = 'OK - RAID status is good - Nb Ctrl : ' + str(nb_ctrl) + ' - Nb Array : ' + str(nb_array) + ' - Nb logicaldrive : ' + str(nb_logical) + ' - Nb physicaldrive : ' + str(nb_physical) tosend = tosend.strip('^\n') logger.debug(str(tosend)) except Exception as e: tosend = str(e) logger.debug('--Debug-- Exception : ' + tosend) print('--Debug-- Exception : ' + tosend) finally: print(str(tosend)) if nb_critical != 0: raise SystemExit, 2 elif nb_warning != 0: raise SystemExit, 1 elif nb_unknown != 0: raise SystemExit, 3 else: raise SystemExit, 0 sys.exit(0) Save