MENU

megaclisas-status

April 1, 2019 • Read: 378 • 笔记阅读设置

#!/usr/bin/python

import os
import re
import sys

binarypath = "/usr/bin/megacli"

# Adding a quick check to see if we're root, because on most cards I've tried this on
# We need root access to query
if __name__ == '__main__':
    if os.getenv('USER') != 'root':
        print 'You can only run this script as root or with sudo, sucks I know. Blame the RAID card'
        sys.exit(5)

if len(sys.argv) > 2:
    print 'Usage: megaclisas-status [--nagios]'
    sys.exit(1)

nagiosmode = False
nagiosoutput = ''
nagiosgoodarray = 0
nagiosbadarray = 0
nagiosgooddisk = 0
nagiosbaddisk = 0

# Check command line arguments to enable nagios or not
if len(sys.argv) > 1:
    if sys.argv[1] == '--nagios':
        nagiosmode = True
    else:
        print 'Usage: megaclisas-status [--nagios]'
        sys.exit(1)

# Check binary exists (and +x), if not print an error message
# or return UNKNOWN nagios error code
if os.path.exists(binarypath) and os.access(binarypath, os.X_OK):
    pass
else:
    if nagiosmode:
        print 'UNKNOWN - Cannot find ' + binarypath
    else:
        print 'Cannot find ' + binarypath + '. Please install it.'
    sys.exit(3)


# Get command output
def getOutput(cmd):
    output = os.popen(cmd)
    lines = []
    for line in output:
        line = line.strip()
        if not re.match(r'^$', line):
            lines.append(line)
    return lines


def returnControllerNumber(output):
    for line in output:
        line = line.strip()
        if re.match(r'^Controller Count.*$', line):
            return int(line.split(':')[1].strip().strip('.'))


def returnControllerModel(output):
    for line in output:
        if re.match(r'^Product Name.*$', line.strip()):
            return line.split(':')[1].strip()
            
def returnControllerFirmware(output):
    for line in output:
        if re.match(r'^FW Package Build.*$', line.strip()):
            return line.split(':')[1].strip()


def returnArrayNumber(output):
    i = 0
    for line in output:
        if re.match(r'^Number of Virtual (Disk|Drive).*$', line.strip()):
            i = line.split(':')[1].strip()
    return i

def returnNextArrayNumber(output,curNumber):
    #Virtual Drive: 2 (Target Id: 2)
    for line in output:
    vdisk = re.match(r'^Virtual Drive: \d+ \(Target Id: (\d+)\)$', line.strip())
        if vdisk and int(vdisk.group(1)) > curNumber:
        return int(vdisk.group(1))
    return -1

def returnArrayInfo(output, controllerid, arrayid):
    _id = 'c%du%d' % (controllerid, arrayid)
    operationlinennumber = False
    linenumber = 0
    ldpdcount = 0
    spandepth = 0

    for line in output:
        line = line.strip()
        if re.match(r'Number Of Drives\s*((per span))?:.*[0-9]+$', line):
            ldpdcount = line.split(':')[1].strip()
        if re.match(r'Span Depth *:.*[0-9]+$', line):
            spandepth = line.split(':')[1].strip()
        if re.match(r'^RAID Level\s*:.*$', line):
            raidlevel = line.split(':')[1].split(',')[0].split('-')[1].strip()
            raid_type = 'RAID' + raidlevel
        if re.match(r'^Size\s*:.*$', line):
            # Size reported in MB
            if re.match(r'^.*MB$', line.split(':')[1]):
                size = line.split(':')[1].strip('MB').strip()
                size = str(int(round((float(size) / 1000)))) + 'G'
            # Size reported in TB
            elif re.match(r'^.*TB$', line.split(':')[1]):
                size = line.split(':')[1].strip('TB').strip()
                size = str(int(round((float(size) * 1000)))) + 'G'
            # Size reported in GB (default)
            else:
                size = line.split(':')[1].strip('GB').strip()
                size = str(int(round((float(size))))) + 'G'
        if re.match(r'^State\s*:.*$', line):
            state = line.split(':')[1].strip()
        if re.match(r'^Ongoing Progresses\s*:.*$', line):
            operationlinennumber = linenumber
        linenumber += 1
        if operationlinennumber:
            inprogress = output[operationlinennumber + 1]
        else:
            inprogress = 'None'

    if ldpdcount and (int(spandepth) > 1):
        ldpdcount = int(ldpdcount) * int(spandepth)
        if int(raidlevel) < 10:
            raid_type = raid_type + "0"

    return [_id, raid_type, size, state, inprogress]


def returnDiskInfo(output, controllerid):
    arrayid = False
    diskid = False
    table = []
    state = 'undef'
    model = 'undef'
    for line in output:
        line = line.strip()
        if re.match(r'^Virtual (Disk|Drive): [0-9]+.*$', line):
            arrayid = line.split('(')[0].split(':')[1].strip()
        if re.match(r'Firmware state: .*$', line):
            state = line.split(':')[1].strip()
        if re.match(r'Inquiry Data: .*$', line):
            model = line.split(':')[1].strip()
            model = re.sub(' +', ' ', model)
        if re.match(r'PD: [0-9]+ Information.*$', line):
            diskid = line.split()[1].strip()

        if arrayid and state != 'undef' and model != 'undef' and diskid:
            table.append([str(arrayid), str(diskid), state, model])
            state = 'undef'
            model = 'undef'

    return table

cmd = binarypath + ' -adpCount -NoLog'
output = getOutput(cmd)
controllernumber = returnControllerNumber(output)

bad = False

# List available controller
if not nagiosmode:
    print '-- Controller informations --'
    print '-- ID | Model | Firmware'
    controllerid = 0
    while controllerid < controllernumber:
        cmd = '%s -AdpAllInfo -a%d -NoLog' % (binarypath, controllerid)
        output = getOutput(cmd)
        controllermodel = returnControllerModel(output)
    firmwareversion = returnControllerFirmware(output)
        print 'c%d | %s | %s' % (controllerid, controllermodel, firmwareversion)
        controllerid += 1
    print ''

controllerid = 0
if not nagiosmode:
    print '-- Arrays informations --'
    print '-- ID | Type | Size | Status | InProgress'

while controllerid < controllernumber:
    cmd = '%s -LdInfo -Lall -a%d -NoLog' % (binarypath, controllerid)
    arrayoutput = getOutput(cmd)
    arrayid = returnNextArrayNumber(arrayoutput,-1)
    cmd = '%s -LdGetNum -a%d -NoLog' % (binarypath, controllerid)
    output = getOutput(cmd)
    arraynumber = int(returnArrayNumber(output))
    while arraynumber > 0:
        cmd = '%s -LDInfo -l%d -a%d -NoLog' % (binarypath,
                                                arrayid, controllerid)
        output = getOutput(cmd)
        arrayinfo = returnArrayInfo(output, controllerid, arrayid)
        if not nagiosmode:
            print ' | '.join(arrayinfo)
        if not arrayinfo[3] == 'Optimal':
            bad = True
            nagiosbadarray += 1
        else:
            nagiosgoodarray += 1
        #arrayid += 1
    arrayid = returnNextArrayNumber(arrayoutput,arrayid)
    arraynumber -= 1
    controllerid += 1
if not nagiosmode:
    print ''

if not nagiosmode:
    print '-- Disks informations'
    print '-- ID | Model | Status'

controllerid = 0
while controllerid < controllernumber:
    arrayid = 0
    cmd = '%s -LDInfo -lall -a%d -NoLog' % (binarypath, controllerid)
    output = getOutput(cmd)
    cmd = '%s -LdPdInfo -a%d -NoLog' % (binarypath, controllerid)
    output = getOutput(cmd)
    arraydisk = returnDiskInfo(output, controllerid)
    for array in arraydisk:
        if not array[2] == 'Online' and not array[2] == 'Online, Spun Up':
            bad = True
            nagiosbaddisk += 1
        else:
            nagiosgooddisk += 1
        if not nagiosmode:
            print 'c%du%sp%s | %s | %s' % (controllerid, array[0],
                    array[1], array[3], array[2])
    controllerid += 1

if nagiosmode:
    status_line = 'Arrays: OK:%d Bad:%d - Disks: OK:%d Bad:%d' % \
                (nagiosgoodarray, nagiosbadarray, nagiosgooddisk, nagiosbaddisk)
    if bad:
        print 'RAID ERROR - ' + status_line
        sys.exit(2)
    else:
        print 'RAID OK - ' + status_line
else:
    if bad:
        print '\nThere is at least one disk/array in a NOT OPTIMAL state.'
        sys.exit(1)

https://github.com/npinto/megaclisas-status

Archives QR Code
QR Code for this page
Tipping QR Code