#!/usr/bin/perl

#
# $Id: check_raid_megarc.pl 191 2007-04-10 18:39:51Z seklecki $
#

#######################################
### check_raid_megarc_cli.pl ##########
###  by Brian A. Seklecki for #########
###   Collaborative Fusion, Inc. ######
#######################################
### This program parses the output ####
### of ports/sysutils/megarc ##########
### It's ugly, and why? Because  ######
### Dell, LSI, and AMI can't agree on #
### a platform-independant kernel #####   
### status interface other than the ###
### CLI.   ############################
#######################################

#/*
# * Copyright (c) 2006-2007 Collaborative Fusion, Inc.  All rights reserved.
# * 
# * Developed by: Collaborative Fusion, Inc.
# *                                                     http://www.collaborativefusion.com
# * 
# * Permission is hereby granted, free of charge, to any person obtaining a copy
# * of this software and associated documentation files (the "Software"), to
# * deal with the Software without restriction, including without limitation the
# * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# * sell copies of the Software, and to permit persons to whom the Software is
# * furnished to do so, subject to the following conditions:
# *   1. Redistributions of source code must retain the above copyright notice,
# *      this list of conditions and the following disclaimers.
# *   2. Redistributions in binary form must reproduce the above copyright
# *      notice, this list of conditions and the following disclaimers in the
# *      documentation and/or other materials provided with the distribution.
# *   3. All advertising materials mentioning features or use of this software
# *      must display the following acknowledgement: This product includes 
# *      software developed by Collaborative Fusion, Inc.
# *   4. Neither the name of Collaborative Fusion, Inc. or any of its employees
# *      may be used to endorse or promote products derived from this Software
# *      without specific prior written permission.
#
# * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
# * COLLABORATIVE FUSION, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
# * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# */
#
#/*
# * This code was written under funding by Collaborative Fusion, Inc..
# */

use warnings;
use strict;
#use Switch;

my %NAGIOS_API_ECODES = ( 'OK' => 0, 'WARNING' => 1, 'CRITICAL' => 2, 'UNKNOWN' => 3 );


my $_strMegarcPath = "/usr/local/sbin/megarc";

# Note, I don't want to include/depend getopt:: yet because
# I once read somewhere (msdn?) that code should be 
# efficient if at all possible ~BAS


my $_intLDCount = 0;
my $_intDegCount = 0;
my @_arrLDStatus;
my $_intFailedComponentCount = 0;
my @_arrFailedComponent;
my $_boolVerbose = 0;

my $USAGE = "Usage:
$0 [-h | <intAdapterNumber =~ [0-9]?> [-v]\n";

if (@ARGV < 1) {
	print $USAGE;
	exit $NAGIOS_API_ECODES{UNKNOWN};
}
	

if ($ARGV[0] !~ m/^[0-9]?$/) {
	print $USAGE;
	exit $NAGIOS_API_ECODES{UNKNOWN};
}

# Check $ARGV[] size before trying to evaluate
# $ARGV[1] otherwise Perl complains like a little wench

if (@ARGV > 1) { 

	if ($ARGV[1] =~ m/^\-v$/) {
		$_boolVerbose = 1;
	}
}

# This abosolute path might need [to be] adjusted
# Gee I wonder if it should be a variable you declare

if (! open(MEGARC, "$_strMegarcPath -dispCfg -a$ARGV[0]|") ) {
	die "Cannot locate megarc(8) binary in \$PATH\n";
	exit $NAGIOS_API_ECODES{UNKNOWN}; 
}

# NOTE: The above could be adjusted to use "-ldInfo" thus allowing $ARGV[1] to specify a 
# check of a specific logical drive...perhaps a future feature

my $_intBus = 0;
my $_intID = 0;

while (my $line = <MEGARC>) {

	if ($line =~ m/^\s+Logical\ Drive\ \:\ ([0-9]+)\(\ Adapter\:\ [0-9]+\ \)\:\ +Status\:\ (OPTIMAL|DEGRADED)\s+$/) {
		$_arrLDStatus[$_intLDCount][0] = $1;
		$_arrLDStatus[$_intLDCount][1] = $2;
		if ($2 =~ "DEGRADED") { $_intDegCount++; }
		$_intLDCount++;
		
	} elsif ($line =~ m/^\s+(\d{1,1})\s+(\d{2,2})\s+0x\d{8,8}\s+0x\w{8,8}\s+(ONLINE|FAILED)\s*$/) {
		$_intBus = $1;
		$_intID = $2;

		if ($3 =~ "FAILED") { 
			$_arrFailedComponent[$_intFailedComponentCount][0] = $_intBus;
			$_arrFailedComponent[$_intFailedComponentCount][1] = $_intID;
			$_intFailedComponentCount++;
		}
	}
	


}

# Goal:  The make the output about as easily parseable as 
# AMI/LSI/Dell have made that of megarc(8)

if ($_intLDCount < 1 ) {
	print "No logical drives found"; exit $NAGIOS_API_ECODES{WARN};
} else { 
	print "$_intLDCount LDs; $_intDegCount degraded";
	if ($_boolVerbose) { 
		print "; $_intFailedComponentCount components failed";
	}
	print "::";
}

my $_intCount = 0;

foreach (@_arrLDStatus) { 
	print "(LD$_arrLDStatus[$_intCount][0] ";
	print "Status: $_arrLDStatus[$_intCount][1] )";
	$_intCount++;
}

if ($_boolVerbose && @_arrFailedComponent > 0) {
	my $_intBadCounter = 0;
	foreach (@_arrFailedComponent) {
		#print "DEBUG: $_intBadCounter\n";
		print " Drive @ Bus[$_arrFailedComponent[$_intBadCounter][0]]-ID[$_arrFailedComponent[$_intBadCounter][1]] OFFLINE!";
		$_intBadCounter++;
	}
}


if ($_intDegCount > 0) {
	 exit $NAGIOS_API_ECODES{CRITICAL};
} else {
	 exit $NAGIOS_API_ECODES{OK};
}
