#!/usr/bin/python

import os
import re
import sys

binarypath = "/usr/sbin/megacli"

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:
		if not re.match(r'^$',line.strip()):
			lines.append(line.strip())
	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 returnControllerModel(output):
	for line in output:
		if re.match(r'^Product Name.*$',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.strip().split(':')[1].strip()
	return i

def returnArrayInfo(output,controllerid,arrayid):
	id = 'c'+str(controllerid)+'u'+str(arrayid)
	operationlinennumber = False
	linenumber = 0

	for line in output:
		if re.match(r'Number Of Drives\s*((per span))?:.*[0-9]+$',line.strip()):
			ldpdcount = line.split(':')[1].strip()
		if re.match(r'Span Depth *:.*[0-9]+$',line.strip()):
			spandepth = line.split(':')[1].strip()
		if re.match(r'^RAID Level\s*:.*$',line.strip()):
			raidlevel = line.strip().split(':')[1].split(',')[0].split('-')[1].strip()
			type = 'RAID' + raidlevel
		if re.match(r'^Size\s*:.*$',line.strip()):
			# Size reported in MB
			if re.match(r'^.*MB$',line.strip().split(':')[1]):
				size = line.strip().split(':')[1].strip('MB').strip()
				size = str(int(round((float(size) / 1000))))+'G'
			# 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'
		if re.match(r'^State\s*:.*$',line.strip()):
			state = line.strip().split(':')[1].strip()
		if re.match(r'^Ongoing Progresses\s*:.*$',line.strip()):
			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:
			type = type + "0"

	return [id,type,size,state,inprogress]

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

		if arrayid != False and state != 'undef' and model != 'undef' and diskid != False:
			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'
	controllerid = 0
	while controllerid < controllernumber:
		cmd = binarypath+' -AdpAllInfo -a'+str(controllerid)+' -NoLog'
		output = getOutput(cmd)
		controllermodel = returnControllerModel(output)
		print 'c'+str(controllerid)+' | '+controllermodel
		controllerid += 1
	print ''

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

while controllerid < controllernumber:
	arrayid = 0
	cmd = binarypath+' -LdGetNum -a'+str(controllerid)+' -NoLog'
	output = getOutput(cmd)
	arraynumber = returnArrayNumber(output)
	while arrayid < int(arraynumber):
		cmd = binarypath+' -LDInfo -l'+str(arrayid)+' -a'+str(controllerid)+' -NoLog'
		output = getOutput(cmd)
		arrayinfo = returnArrayInfo(output,controllerid,arrayid)
		if not nagiosmode:
			print arrayinfo[0]+' | '+arrayinfo[1]+' | '+arrayinfo[2]+' | '+arrayinfo[3]+' | '+arrayinfo[4]
		if not arrayinfo[3] == 'Optimal':
			bad = True
			nagiosbadarray=nagiosbadarray+1
		else:
			nagiosgoodarray=nagiosgoodarray+1
		arrayid += 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 = binarypath+' -LDInfo -lall -a'+str(controllerid)+' -NoLog'
	output = getOutput(cmd)
	cmd = binarypath+' -LdPdInfo -a'+str(controllerid)+' -NoLog'
	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=nagiosbaddisk+1
		else:
			nagiosgooddisk=nagiosgooddisk+1
		if not nagiosmode:
			print 'c'+str(controllerid)+'u'+array[0]+'p'+array[1]+' | '+array[3]+' | '+array[2]
	controllerid += 1

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)