diff --git a/map-osd-to-disktype b/map-osd-to-disktype new file mode 100644 index 0000000..f1a2ff8 --- /dev/null +++ b/map-osd-to-disktype @@ -0,0 +1,13 @@ +# Assumes, osd is up and + +# Tempfile +./megacli-status > /tmp/megaclisas-status.out + +# Gets osd numbers of a particular device class, and gets their mountpoints on the host, and puts them into a tempfile +for osd in $(ceph osd tree | grep $OSD | grep -v down | cut -b 1-3); do findmnt -t xfs -n -o TARGET,SOURCE | grep $osd| cut -c 24- >> /tmp/list_osd_mountpoint; done + +# Gets the Megacli mappings for the mountpoints +for MOUNT in $(cat /tmp/list_osd_mountpoint | awk '{print $2}' | sed 's/[0-9]*//g') ; do cat /tmp/megaclisas-status.out | grep $MOUNT | awk '{print $1}' >> /tmp/megacli-mappings.out; done + +# Gets the hardware types for the Megacli mappings +for i in $(cat /tmp/megacli-mappings.out); do awk '/Disk info/,0' /tmp/megaclisas-status.out | grep $i | cut -d '|' -f 3 >> /tmp/disk_types; done diff --git a/megaclisas-status b/megaclisas-status new file mode 100755 index 0000000..3495502 --- /dev/null +++ b/megaclisas-status @@ -0,0 +1,875 @@ +#!/usr/bin/python +# $Id: megaclisas-status,v 1.68 2016/10/21 14:38:56 root Exp root $ +# +# Written by Adam Cecile +# Modified by Vincent S. Cojot +# + +import os +import re +import sys +import pdb +if sys.platform == 'win32': + import ctypes + +def_megaclipath = "/opt/MegaRAID/MegaCli/MegaCli64" + +# Non-Nagios Mode defaults +nagiosmode = False +nagiosoutput='' +nagiosgoodarray = 0 +nagiosbadarray = 0 +nagiosgooddisk = 0 +nagiosbaddisk = 0 + +# Sane defaults +printarray = True +printcontroller = True +debugmode = False +notempmode = False +totaldrivenumber = 0 + +# Hardcode a max of 16 HBA and 128 LDs for now. LDTable must be initialized to accept populating list of LD's into each ctlr's list. +MaxNumHBA = 16 +MaxNumLD = 128 +LDTable = [ [] * MaxNumHBA for i in range(MaxNumLD) ] +NestedLDTable = [[False for i in range(MaxNumHBA)] for j in range(MaxNumLD)] + +# Outputs is a 'dict' of all MegaCLI outputs so we can re-use them during loops.. +Outputs = {} + +# Startup +def print_usage(): + print 'Usage: megaraid-status [--nagios|--debug|--notemp]' + +# We need root access to query +if __name__ == '__main__': + try: + root_or_admin = os.geteuid() == 0 + except AttributeError: + root_or_admin = ctypes.windll.shell32.IsUserAnAdmin() !=0 + if not root_or_admin: + print '# This script requires Administrator privileges' + sys.exit(5) + +# Check command line arguments to enable nagios or not +if len(sys.argv) > 2: + print_usage() + sys.exit(1) + +if len(sys.argv) > 1: + if sys.argv[1] == '--nagios': + nagiosmode = True + elif sys.argv[1] == '--debug': + debugmode = True + elif sys.argv[1] == '--notemp': + notempmode = True + else: + print_usage() + sys.exit(1) +# Functions +def dbgprint(msg): + if (debugmode): + sys.stderr.write ( str('# DEBUG : '+msg+'\n')) + +def is_exe(fpath): + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + +def which(program): + import os + fpath, fname = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + # Add some defaults + os.environ["PATH"] += os.pathsep + '/opt/MegaRAID/MegaCli' + os.environ["PATH"] += os.pathsep + '/ms/dist/hwmgmt/bin' + os.environ["PATH"] += os.pathsep + os.path.dirname(os.path.realpath(sys.argv[0])) + for path in os.environ["PATH"].split(os.pathsep): + dbgprint ('Looking in PATH '+str(path)) + path = path.strip('"') + exe_file = os.path.join(path, program) + if is_exe(exe_file): + dbgprint ('Found "'+program+'" at '+exe_file) + return exe_file + return None + +# Find MegaCli +for megabin in "MegaCli64","MegaCli","megacli", "MegaCli.exe": + dbgprint ('Looking for '+str(megabin)+' in PATH next..') + megaclipath = which(megabin) + if (megaclipath != None): + dbgprint ('Will use MegaCLI from here: '+str(megaclipath)) + break + +# Check binary exists (and +x), if not print an error message +if (megaclipath != None): + if os.path.exists(megaclipath) and os.access(megaclipath, os.X_OK): + pass + else: + if nagiosmode: + print 'UNKNOWN - Cannot find '+megaclipath + else: + print 'Cannot find ' + megaclipath + 'in your PATH. Please install it.' + sys.exit(3) +else: + print 'Cannot find "MegaCli64","MegaCli" or "megacli" or "MegaCli.exe" in your PATH. Please install it.' + sys.exit(3) + + +#### pdb.set_trace() + +def returnWdthFromArrayCol(glarray,idx): + maxwdth = 0 + for glrow in glarray: + if ( len(glrow[idx]) > maxwdth): + maxwdth = len(glrow[idx]) + return maxwdth + +# Get command output +def getOutput(cmd): + lines = [] + if ( Outputs.has_key(cmd) ): + dbgprint ("Got Cached value: "+str(cmd)) + lines = Outputs[cmd] + else: + dbgprint ("Not a Cached value: "+str(cmd)) + output = os.popen(cmd) + for line in output: + if not re.match(r'^$',line.strip()): + lines.append(line.strip()) + Outputs[cmd] = lines + return lines + +def returnControllerNumber(output): + for line in output: + if re.match(r'^Controller Count.*$',line.strip()): + return int(line.split(':')[1].strip().strip('.')) + +def returnTotalDriveNumber(output): + for line in output: + if re.match(r'Number of Physical Drives on Adapter.*$',line.strip()): + return int(line.split(':')[1].strip()) + +def returnRebuildProgress(output): + percent = 0 + tmpstr = '' + for line in output: + if re.match(r'^Rebuild Progress on Device at Enclosure.*, Slot .* Completed ',line.strip()): + tmpstr = line.split('Completed')[1].strip() + percent = int(tmpstr.split('%')[0].strip()) + return percent + +def returnConfDriveNumber(output): + # Count the configured drives + confdrives = 0 + for line in output: + if re.match(r'.*Number of PDs:.*$',line.strip()): + confdrives += int(line.split(':')[2].strip()) + return int(confdrives) + +def returnUnConfDriveNumber(output): + # Count the configured drives + confdrives = 0 + for line in output: + if re.match(r'^Firmware state: Unconfigured.*$',line.strip()): + confdrives += 1 + return int(confdrives) + +def returnControllerModel(output): + for line in output: + if re.match(r'^Product Name.*$',line.strip()): + return line.split(':')[1].strip() + +def returnMemorySize(output): + for line in output: + if re.match(r'^Memory Size.*$',line.strip()): + return line.split(':')[1].strip() + +def returnFirmwareVersion(output): + for line in output: + if re.match(r'^FW Package Build.*$',line.strip()): + return line.split(':')[1].strip() + +def returnROCTemp(output): + ROCtemp = '' + tmpstr = '' + if (notempmode): + return str('N/A') + else: + for line in output: + if re.match(r'^ROC temperature :.*$',line.strip()): + tmpstr = line.split(':')[1].strip() + ROCtemp = re.sub(' +.*$', '', tmpstr) + if ( ROCtemp != '' ): + return str(str(ROCtemp)+'C') + else: + return str('N/A') + +def returnBBUPresence(output): + BBU = '' + tmpstr = '' + for line in output: + if re.match(r'^BBU +:.*$',line.strip()): + tmpstr = line.split(':')[1].strip() + BBU = re.sub(' +.*$', '', tmpstr) + break + if ( BBU != '' ): + return str(BBU) + else: + return str('N/A') + +def returnBBUStatus(output): + BBUStatus = '' + tmpstr = '' + for line in output: + if re.match(r'^ *Battery Replacement required +:.*$',line.strip()): + tmpstr = line.split(':')[1].strip() + BBUStatus = re.sub(' +.*$', '', tmpstr) + break + if ( BBUStatus == 'Yes' ): + return str('REPL') + else: + return str('Good') + +def returnArrayNumber(output): + i = 0 + for line in output: + if re.match(r'^(CacheCade )?Virtual Drive:.*$',line.strip()): + i += 1 + return i + +def returnHBAPCIInfo(output): + busprefix = '0000' + busid = '' + devid = '' + functionid = '' + pcipath = '' + for line in output: + if re.match(r'^Bus Number.*:.*$',line.strip()): + busid = str(line.strip().split(':')[1].strip()).zfill(2) + if re.match(r'^Device Number.*:.*$',line.strip()): + devid = str(line.strip().split(':')[1].strip()).zfill(2) + if re.match(r'^Function Number.*:.*$',line.strip()): + functionid = str(line.strip().split(':')[1].strip()).zfill(1) + if busid: + pcipath = str(busprefix + ':' + busid + ':' + devid + '.' + functionid) + dbgprint("Array PCI path : "+pcipath) + return str(pcipath) + else: + return None + +def returnHBAInfo(table,output,controllerid): + controllermodel = 'Unknown' + controllerram = 'Unknown' + controllerrev = 'Unknown' + controllertemp = '' + controllermodel = returnControllerModel(output) + controllerram = returnMemorySize(output) + controllerrev = returnFirmwareVersion(output) + controllertemp = returnROCTemp(output) + controllerbbu = returnBBUPresence(output) + if controllerbbu == 'Present': + cmd = '%s -AdpBbuCmd -GetBbuStatus -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + controllerbbu = returnBBUStatus(output) + + if controllermodel != 'Unknown': + table.append([ 'c'+str(controllerid), controllermodel, controllerram, str(controllertemp), str(controllerbbu), str('FW: '+controllerrev) ]) + +def returnArrayInfo(output,controllerid,arrayid,arrayindex): + id = 'c'+str(controllerid)+'u'+str(arrayid) + operationlinennumber = False + linenumber = 0 + targetid = '' + raidtype = '' + raidlvl = '' + size = '' + state = 'N/A' + strpsz = '' + dskcache = 'N/A' + properties = '' + spandepth = 0 + diskperspan = 0 + cachecade_info = 'None' + + for line in output: + if re.match(r'^(CacheCade )?Virtual Drive:.*(Target Id: [0-9]+).*$',line.strip()): + # Extract the SCSI Target ID + targetid = line.strip().split(':')[2].split(')')[0].strip() + elif re.match(r'^RAID Level.*?:.*$',line.strip()): + # Extract the primary raid type, decide on X0 RAID level later when we hit Span Depth + raidlvl = int(line.strip().split(':')[1].split(',')[0].split('-')[1].strip()) + elif re.match(r'^Size.*?:.*$',line.strip()): + # Size reported in MB + if re.match(r'^.*MB$',line.strip().split(':')[1]): + size = line.strip().split(':')[1].strip('MB').strip() + if ( float(size) > 1000): + size = str(int(round((float(size) / 1000))))+'G' + else: + size = str(int(round(float(size))))+'M' + # Size reported in TB + elif re.match(r'^.*TB$',line.strip().split(':')[1]): + size = line.strip().split(':')[1].strip('TB').strip() + size = str(int(round((float(size) * 1000))))+'G' + # Size reported in GB (default) + else: + size = line.strip().split(':')[1].strip('GB').strip() + size = str(int(round((float(size)))))+'G' + elif re.match(r'^Span Depth.*?:.*$',line.strip()): + # If Span Depth is greater than 1 chances are we have a RAID 10, 50 or 60 + spandepth = line.strip().split(':')[1].strip() + elif re.match(r'^State.*?:.*$',line.strip()): + state = line.strip().split(':')[1].strip() + elif re.match(r'^Strip Size.*?:.*$',line.strip()): + strpsz = line.strip().split(':')[1].strip() + elif re.match(r'^Number Of Drives per span.*:.*$',line.strip()): + diskperspan = int(line.strip().split(':')[1].strip()) + elif re.match(r'^Current Cache Policy.*?:.*$',line.strip()): + props = line.strip().split(':')[1].strip() + if re.search('ReadAdaptive', props): + properties += 'ADRA' + if re.search('ReadAhead', props): + properties += 'RA' + if re.match('ReadAheadNone', props): + properties += 'NORA' + if re.search('WriteBack', props): + properties += ',WB' + if re.match('WriteThrough', props): + properties += ',WT' + elif re.match(r'^Disk Cache Policy.*?:.*$',line.strip()): + props = line.strip().split(':')[1].strip() + if re.search('Disabled', props): + dskcache = 'Disabled' + if re.search('Disk.s Default', props): + dskcache = 'Default' + if re.search('Enabled', props): + dskcache = 'Enabled' + elif re.match(r'^Ongoing Progresses.*?:.*$',line.strip()): + operationlinennumber = linenumber + elif re.match(r'Cache Cade Type\s*:.*$', line): + cachecade_info = "Type : " + line.strip().split(':')[1].strip() + elif re.match(r'^Target Id of the Associated LDs\s*:.*$', line): + associated=[] + for array in line.split(':')[1].strip().split(','): + if array.isdigit(): + associated.append('c%du%d' % (controllerid, int(array))) + if len(associated) >= 1: + cachecade_info = "Associated : %s" %(', '.join(associated)) + linenumber += 1 + + # If there was an ongoing operation, find the relevant line in the previous output + if operationlinennumber: + inprogress = output[operationlinennumber + 1] + else: + inprogress = 'None' + + # Compute the RAID level + NestedLDTable[int(controllerid)][int(arrayindex)] = False + if raidlvl == '': + raidtype = str('N/A') + else: + if (int(spandepth) >= 2): + raidtype = str('RAID-' + str(raidlvl) + '0') + NestedLDTable[controllerid][int(arrayindex)] = True + else: + if(raidlvl == 1): + if(diskperspan > 2): + raidtype = str('RAID-10') + NestedLDTable[controllerid][int(arrayindex)] = True + else: + raidtype = str('RAID-' + str(raidlvl)) + else: + raidtype = str('RAID-' + str(raidlvl)) + + dbgprint('RAID Level: ' + str(raidlvl) + + ' Span Depth: ' + str(spandepth) + + ' Disk Per Span: ' + str(diskperspan) + + ' Raid Type: ' + str(raidtype)) + return [id,raidtype,size,strpsz,properties,dskcache,state,targetid,cachecade_info,inprogress] + +def returnDiskInfo(output,controllerid): + arrayid = False + arrayindex = -1 + sarrayid = 'Unknown' + diskid = False + oldenclid = False + enclid = False + spanid = False + slotid = False + lsidid = 'Unknown' + table = [] + fstate = 'Offline' + substate = 'Unknown' + model = 'Unknown' + speed = 'Unknown' + dsize = 'Unknown' + temp = 'Unk0C' + percent = 0 + for line in output: + if re.match(r'^Span: [0-9]+ - Number of PDs:',line.strip()): + spanid = line.split(':')[1].strip() + spanid = re.sub(' - Number of PDs.*', '', spanid) + elif re.match(r'Enclosure Device ID: .*$',line.strip()): + # We match here early in the analysis so reset the vars if this is a new disk we're reading.. + oldenclid = enclid + enclid = line.split(':')[1].strip() + if oldenclid != False: + fstate = 'Offline' + model = 'Unknown' + speed = 'Unknown' + temp = 'Unk0C' + slotid = False + lsidid = 'Unknown' + elif re.match(r'^Coerced Size: ',line.strip()): + dsize = line.split(':')[1].strip() + dsize = re.sub(' \[.*\.*$', '', dsize) + dsize = re.sub('[0-9][0-9] GB', ' Gb', dsize) + elif re.match(r'^(CacheCade )?Virtual (Disk|Drive): [0-9]+.*$',line.strip()): + arrayindex += 1 + arrayid = line.split('(')[0].split(':')[1].strip() + elif re.match(r'PD: [0-9]+ Information.*$',line.strip()): + diskid = line.split()[1].strip() + elif re.match(r'^Device Id: .*$',line.strip()): + lsidid = line.split(':')[1].strip() + elif re.match(r'Slot Number: .*$',line.strip()): + slotid = line.split(':')[1].strip() + elif re.match(r'Firmware state: .*$',line.strip()): + fstate = line.split(':')[1].strip() + subfstate = re.sub('\(.*', '', fstate) + dbgprint('Firmware State: '+str(fstate)+' '+str(subfstate)) + elif re.match(r'Inquiry Data: .*$',line.strip()): + model = line.split(':')[1].strip() + model = re.sub(' +', ' ', model) + # Sub code + manuf = re.sub(' .*', '', model) + dtype = re.sub(manuf+' ', '', model) + dtype = re.sub(' .*', '', dtype) + hwserial = re.sub('.*'+dtype+' *', '', model) + elif re.match(r'^Media Type: .*$',line.strip()): + mtype = line.split(':')[1].strip() + if mtype == 'Hard Disk Device': + mtype = 'HDD' + else: + if mtype == 'Solid State Device': + mtype = 'SSD' + else: + mtype = 'N/A' + elif re.match(r'Device Speed: .*$',line.strip()): + speed = line.split(':')[1].strip() + elif re.match(r'Drive Temperature :.*$',line.strip()): + if (notempmode): + temp = 'N/A' + else: + # Drive temp is amongst the last few lines matched, decide here if we add information to the table.. + temp = line.split(':')[1].strip() + temp = re.sub(' \(.*\)', '', temp) + if model != 'Unknown': + dbgprint('Disk Info: '+str(arrayid)+' '+str(diskid)+' '+str(oldenclid)) + if subfstate == 'Rebuild': + cmd = '%s pdrbld -showprog -physdrv\[%s:%s\] -a%d -NoLog' % (megaclipath, enclid, slotid, controllerid) + output = getOutput(cmd) + percent = returnRebuildProgress(output) + fstate = str('Rebuilding (%d%%)' % (percent)) + + if (( NestedLDTable[controllerid][int(arrayindex)] == True) and (spanid != False)): + sarrayid = str(arrayid)+"s"+spanid + else: + sarrayid = str(arrayid) + table.append([sarrayid, str(diskid), mtype, model, dsize, fstate , speed, temp, enclid, slotid, lsidid]) + return table + + +def returnUnconfDiskInfo(output,controllerid): + arrayid = False + diskid = False + olddiskid = False + enclid = False + slotid = False + lsidid = 'Unknown' + table = [] + fstate = 'Offline' + substate = 'Unknown' + model = 'Unknown' + speed = 'Unknown' + mtype = 'Unknown' + dsize = 'Unknown' + temp = 'Unk0C' + for line in output: + if re.match(r'Enclosure Device ID: .*$',line.strip()): + # We match here early in the analysis so reset the vars if this is a new disk we're reading.. + oldenclid = enclid + enclid = line.split(':')[1].strip() + if oldenclid != False: + arrayid = False + fstate = 'Offline' + model = 'Unknown' + speed = 'Unknown' + temp = 'Unk0C' + slotid = False + lsidid = 'Unknown' + + elif re.match(r'^Coerced Size: ',line.strip()): + dsize = line.split(':')[1].strip() + dsize = re.sub(' \[.*\.*$', '', dsize) + dsize = re.sub('[0-9][0-9] GB', ' Gb', dsize) + elif re.match(r'^Drive.s position: DiskGroup: [0-9]+,.*$',line.strip()): + arrayid = line.split(',')[1].split(':')[1].strip() + elif re.match(r'^Device Id: [0-9]+.*$',line.strip()): + diskid = line.split(':')[1].strip() + elif re.match(r'^Device Id: .*$',line.strip()): + lsidid = line.split(':')[1].strip() + elif re.match(r'Slot Number: .*$',line.strip()): + slotid = line.split(':')[1].strip() + elif re.match(r'Firmware state: .*$',line.strip()): + fstate = line.split(':')[1].strip() + subfstate = re.sub('\(.*', '', fstate) + dbgprint('Firmware State: '+str(fstate)+' '+str(subfstate)) + elif re.match(r'Inquiry Data: .*$',line.strip()): + model = line.split(':')[1].strip() + model = re.sub(' +', ' ', model) + manuf = re.sub(' .*', '', model) + dtype = re.sub(manuf+' ', '', model) + dtype = re.sub(' .*', '', dtype) + hwserial = re.sub('.*'+dtype+' *', '', model) + elif re.match(r'^Media Type: .*$',line.strip()): + mtype = line.split(':')[1].strip() + if mtype == 'Hard Disk Device': + mtype = 'HDD' + else: + if mtype == 'Solid State Device': + mtype = 'SSD' + else: + mtype = 'N/A' + elif re.match(r'Device Speed: .*$',line.strip()): + speed = line.split(':')[1].strip() + elif re.match(r'Drive Temperature :.*$',line.strip()): + temp = line.split(':')[1].strip() + temp = re.sub('\(.*\)', '', temp) + # Drive temp is amongst the last few lines matched, decide here if we add information to the table.. + if arrayid == False: + if subfstate == 'Unconfigured': + dbgprint('Unconfigured Disk: Arrayid: '+str(arrayid)+' DiskId: '+str(diskid)+' '+str(olddiskid)+' '+str(fstate)) + elif subfstate == 'Online, Spun Up': + dbgprint('Online Disk: Arrayid: '+str(arrayid)+' DiskId: '+str(diskid)+' '+str(olddiskid)+' '+str(fstate)) + table.append([ mtype, model, dsize, fstate, speed, temp, enclid, slotid, lsidid]) + return table + +cmd = '%s -adpCount -NoLog' % (megaclipath) +output = getOutput(cmd) +controllernumber = returnControllerNumber(output) + +bad = False + +# List available controller +if printcontroller: + if controllernumber: + if not nagiosmode: + print '-- Controller information --' + + i = 0 + controllerid = 0 + mlen = 0 + hbainfo = [] + while controllerid < controllernumber: + cmd = '%s -AdpAllInfo -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + returnHBAInfo(hbainfo, output,controllerid) + controllerid += 1 + mlen = returnWdthFromArrayCol(hbainfo,1) + + controllerid = 0 + for hba in hbainfo: + hbafmt = str('%-5s | %-'+str(mlen)+'s | %-6s | %-4s | %-6s | %-12s ') + # Header + if ( i == 0 ): + if not nagiosmode: + print hbafmt % ("-- ID","H/W Model","RAM","Temp","BBU", "Firmware") + if not nagiosmode: + print hbafmt % ( + hba[0], + hba[1], + hba[2], + hba[3], + hba[4], + hba[5]) + i += 1 + if not nagiosmode: + print '' + else: + print "No MegaRAID or PERC adapter detected on your system!" + exit(1) + +if printarray: + if not nagiosmode: + print '-- Array information --' + + controllerid = 0 + pcipath = '' + diskpath = '' + i = 0 ; j = 0 + mlen = 0 ; rlen = 0 ; clen = 0 + while controllerid < controllernumber: + arrayindex = 0 + + cmd = '%s -LDInfo -lall -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + arraynumber = returnArrayNumber(output) + # We need to explore each HBA to look for gaps in LD's + ldid = 0 ; ldcount = 0 + while ldcount < arraynumber: + cmd = '%s -LDInfo -l%d -a%d -NoLog' % (megaclipath, ldid, controllerid) + output = getOutput(cmd) + for line in output: + if re.match(r'^Adapter.*Virtual Drive .* Does not Exist',line.strip()): + ldid += 1 + elif re.match(r'^(CacheCade )?Virtual Drive:',line.strip()): + LDTable[controllerid].append ( ldid ) + #NestedLDTable[controllerid][int(arrayindex)] = False + ldcount += 1 + ldid += 1 + + while arrayindex < arraynumber: + ldid = LDTable[controllerid][arrayindex] + cmd = '%s -LDInfo -l%d -a%d -NoLog' % (megaclipath, ldid, controllerid) + output = getOutput(cmd) + arrayinfo = returnArrayInfo(output, controllerid, ldid, arrayindex) + if ( len(arrayinfo[1]) > rlen): + rlen = len(arrayinfo[1]) + if ( len(arrayinfo[4]) > mlen): + mlen = len(arrayinfo[4]) + if ( len(arrayinfo[8]) > clen): + clen = len(arrayinfo[8]) + arrayindex += 1 + controllerid += 1 + + controllerid = 0 + while controllerid < controllernumber: + arrayindex = 0 + + cmd = '%s -AdpGetPciInfo -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + pcipath = returnHBAPCIInfo(output) + + cmd = '%s -LDInfo -lall -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + arraynumber = returnArrayNumber(output) + while arrayindex < arraynumber: + ldid = LDTable[controllerid][arrayindex] + cmd = '%s -LDInfo -l%d -a%d -NoLog' % (megaclipath, ldid, controllerid) + output = getOutput(cmd) + arrayinfo = returnArrayInfo(output,controllerid, ldid, arrayindex) + + if pcipath: + diskprefix = str('/dev/disk/by-path/pci-' + pcipath + '-scsi-0:') + for j in range (8): + diskpath = diskprefix + str(j) + ':' + str(arrayinfo[7]) + ':0' + if os.path.exists(diskpath): + arrayinfo[7] = os.path.realpath(diskpath) + else: + arrayinfo[7] = 'N/A' + + # Pad the string length, just to make sure it's aligned with the headers... + if (rlen < len("Type")): + rlen = len("Type") + if (mlen < len("Flags")): + mlen = len("Flags") + if (clen < len("CacheCade")): + clen = len("CacheCade") + + ldfmt = str('%-5s | %-'+str(rlen)+'s | %7s | %7s | %'+str(mlen)+'s | %8s | %8s | %8s | %-'+str(clen)+'s |%-12s ') + # Header + if ( i == 0 ): + if not nagiosmode: + print ldfmt % ("-- ID", "Type", "Size", "Strpsz", "Flags", "DskCache", "Status", "OS Path", "CacheCade", "InProgress" ) + if not nagiosmode: + print ldfmt % ( + arrayinfo[0], + arrayinfo[1], + arrayinfo[2], + arrayinfo[3], + arrayinfo[4], + arrayinfo[5], + arrayinfo[6], + arrayinfo[7], + arrayinfo[8], + arrayinfo[9]) + dbgprint("Array state : "+arrayinfo[6]) + if arrayinfo[6] not in [ 'Optimal', 'N/A' ]: + bad = True + nagiosbadarray=nagiosbadarray+1 + else: + nagiosgoodarray=nagiosgoodarray+1 + arrayindex += 1 + i += 1 + controllerid += 1 + if not nagiosmode: + print '' + +controllerid = 0 +while controllerid < controllernumber: + cmd = '%s -PDGetNum -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + totaldrivenumber += returnTotalDriveNumber(output) + controllerid += 1 + +if totaldrivenumber: + if not nagiosmode: + print '-- Disk information --' + + i = 0 + dlen = 0 ; mlen = 0 ; flen = 0 + controllerid = 0 + while controllerid < controllernumber: + arrayid = 0 + cmd = '%s -LDInfo -lall -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + arraynumber = returnArrayNumber(output) + #### BUG: -LdPdInfo shows all PD on the adapter, not just for said LD.. + #### while arrayid <= arraynumber: + cmd = '%s -LdPdInfo -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + arraydisk = returnDiskInfo(output,controllerid) + for array in arraydisk: + dbgprint('Disk c'+str(controllerid)+'u'+array[0]+'p'+array[1] + ' status : ' + array[5]) + if array[5] not in [ 'Online', 'Online, Spun Up' ]: + bad = True + nagiosbaddisk=nagiosbaddisk+1 + else: + nagiosgooddisk=nagiosgooddisk+1 + + if ( returnWdthFromArrayCol(arraydisk,0) > dlen): + dlen = returnWdthFromArrayCol(arraydisk,0) + if ( returnWdthFromArrayCol(arraydisk,3) > mlen): + mlen = returnWdthFromArrayCol(arraydisk,3) + if ( returnWdthFromArrayCol(arraydisk,5) > flen): + flen = returnWdthFromArrayCol(arraydisk,5) + controllerid += 1 + + controllerid = 0 + while controllerid < controllernumber: + arrayid = 0 + + cmd = '%s -LDInfo -lall -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + arraynumber = returnArrayNumber(output) + #### BUG: -LdPdInfo shows all PD on the adapter, not just for said LD.. + #### while arrayid <= arraynumber: + + cmd = '%s -LdPdInfo -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + arraydisk = returnDiskInfo(output,controllerid) + + # Adjust print format with width computed above + drvfmt = "%-"+str(dlen+5)+"s | %-4s | %-"+str(mlen)+"s | %-8s | %-"+str(flen)+"s | %-8s | %-4s | %-8s | %-8s" + for array in arraydisk: + # Header + if ( i == 0 ): + if not nagiosmode: + print drvfmt % ( + "-- ID", "Type", "Drive Model", "Size", "Status", "Speed", "Temp", "Slot ID", "LSI Device ID") + # Drive information + if not nagiosmode: + print drvfmt % ( + str('c'+str(controllerid)+'u'+array[0]+'p'+array[1]), # c0p0 + array[2], # HDD/SDD + array[3], # Model Information (Variable len) + array[4], # Size + array[5], # Status (Variable len) + array[6], # Speed + array[7], # Temp + str('['+array[8]+':'+array[9]+']'), # Slot ID + array[10]) # LSI ID + i = i + 1 + controllerid += 1 + if not nagiosmode: + print '' + +controllerid = 0 +totalconfdrivenumber = 0 +totalunconfdrivenumber = 0 +totaldrivenumber = 0 +while controllerid < controllernumber: + cmd = '%s -LdPdInfo -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + totalconfdrivenumber += returnConfDriveNumber(output) + + cmd = '%s -PDGetNum -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + totaldrivenumber += returnTotalDriveNumber(output) + + cmd = '%s -PDList -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + totalunconfdrivenumber += returnUnConfDriveNumber(output) + + controllerid += 1 + +dbgprint('Total Drives in system : ' + str(totaldrivenumber)) +dbgprint('Total Configured Drives : ' + str(totalconfdrivenumber)) +dbgprint('Total Unconfigured Drives : ' + str(totalunconfdrivenumber)) + +if totalunconfdrivenumber: + if not nagiosmode: + print '-- Unconfigured Disk information --' + + controllerid = 0 + while controllerid < controllernumber: + arrayid = 0 + + cmd = '%s -LDInfo -lall -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + arraynumber = returnArrayNumber(output) + #### BUG: -LdPdInfo shows all PD on the adapter, not just for given LD.. + #### while arrayid <= arraynumber: + + cmd = '%s -PDList -a%d -NoLog' % (megaclipath, controllerid) + output = getOutput(cmd) + arraydisk = returnUnconfDiskInfo(output,controllerid) + for array in arraydisk: + dbgprint('Disk c'+str(controllerid)+'uXpY status : ' + array[3]) + if array[3] not in [ 'Online', 'Unconfigured(good), Spun Up', 'Unconfigured(good), Spun down', 'JBOD','Hotspare, Spun Up','Hotspare, Spun down' ]: + bad = True + nagiosbaddisk=nagiosbaddisk+1 + else: + nagiosgooddisk=nagiosgooddisk+1 + + mlen = returnWdthFromArrayCol(arraydisk,1) + flen = returnWdthFromArrayCol(arraydisk,3) + + # Adjust print format with widths computed above + drvfmt = "%-7s | %-4s | %-"+str(mlen)+"s | %-8s | %-"+str(flen+2)+"s | %-8s | %-4s | %-8s | %-8s" + i = 0 + for array in arraydisk: + # Header + if ( i == 0 ): + if not nagiosmode: + print drvfmt % ( + "-- ID", "Type", "Drive Model", "Size", "Status", "Speed", "Temp", "Slot ID", "LSI Device ID") + # Drive information + if not nagiosmode: + print drvfmt % ( + str('c'+str(controllerid)+'uXpY'), # cXpY + array[0], # HDD/SDD + array[1], # Model Information (Variable len) + array[2], # Size + array[3], # Status (Variable len) + array[4], # Speed + array[5], # Temp + str('['+array[6]+':'+array[7]+']'), # Slot ID + array[8]) # LSI ID + i = i + 1 + controllerid += 1 + if not nagiosmode: + print '' + +if nagiosmode: + if bad: + print 'RAID ERROR - Arrays: OK:'+str(nagiosgoodarray)+' Bad:'+str(nagiosbadarray)+' - Disks: OK:'+str(nagiosgooddisk)+' Bad:'+str(nagiosbaddisk) + sys.exit(2) + else: + print 'RAID OK - Arrays: OK:'+str(nagiosgoodarray)+' Bad:'+str(nagiosbadarray)+' - Disks: OK:'+str(nagiosgooddisk)+' Bad:'+str(nagiosbaddisk) +else: + if bad: + print '\nThere is at least one disk/array in a NOT OPTIMAL state.' + sys.exit(1)