#!/usr/bin/perl -T -w

use strict;

# check_is.pl plugin for nagios
#
# usage:
#    check_is.pl [-d] <storage controller ip address or name>
#
# Check the status of an LSI/Engenio storage controller
#
# You will need to have already discovered the controllers you wish to monitor
# with the SMEE utilities.  It is very likely that you will also need to run
# this script with sudo since it needs to run smeecli.  Running smeecli as a
# user other than root is not well supported apparently.
#
# This script parse the output from smeecli -c 'show StorageArray;' looking 
# for failed components.  Since the output from show StorageArray isn't a 
# well-defined standard, it might miss things.  Send fixes and comments to 
# chas@cmf.nrl.navy.mil.

$ENV{PATH} = "/usr/bin:/bin:/usr/sbin:/sbin";

my $SMEECLI = '/opt/smee/client/smeecli';

my @states = ( 'OK', 'WARNING', 'CRITICAL', 'UNKNOWN' );
my $OK = 0;
my $WARNING = 1;
my $CRITICAL = 2;
my $UNKNOWN = 3;

my $checking_controllers = 0;
my $checking_volumegroups = 0;
my $checking_volumes = 0;
my $checking_drives = 0;
my $checking_channels = 0;
my $checking_trays = 0;
my $name;
my $status;
my $dummy;

my $result = $UNKNOWN;	# assume failure
my $retries = 3;
my $retry_timer = 1;

my @errors = '';

my $controller;
my $debug = 0;		# also causes warning (FIXME)

undef $controller;
while ($_ = shift @ARGV) {
	#/-n/ && do {
	#	$controller = shift @ARGV;
	#};
	/-d/ && do { $debug = 1; next; };
	($controller) = /([a-zA-Z0-9\.\-]+)/;	# untaint, only matching valid hostnames
}

if (not defined $controller) {
	printf "check_is.pl <controller ip address or name>\n";
	exit $UNKNOWN;
}

my $cmdline = sprintf "%s %s -quick -c 'show StorageArray;' |", $SMEECLI, $controller;

retry:
open(SMEECLI, $cmdline);

while ($_ = <SMEECLI>) {
	chop;

	#printf "%s\n", $_;

	/smeecli failed/ && do {
		$result = $CRITICAL;
		sleep($retry_timer);			# sleep...
		$retry_timer = $retry_timer * 2;
		if (--$retries == 0) {
			goto out;
		}
		goto retry;				# and try again
	};

	/PROFILE FOR STORAGE ARRAY:/ && do {
		$result = $OK;
	};

	# reset everything if we see a new header
	/-----------$/ && do {
		$checking_controllers = 0;
		$checking_volumegroups = 0;
		$checking_volumes = 0;
		$checking_drives = 0;
		$checking_channels = 0;
		$checking_trays = 0;
	};

	/^CONTROLLERS---/ && ($checking_controllers = 1);
	if ($checking_controllers) {
		/Status:/ && do {
			($dummy, $status) = split;
			if ($status ne 'Online' || $debug) {
				$result = $WARNING;
				push @errors, sprintf "Controller: %s\n", $status;
			};
		};
	};

	/^VOLUME GROUPS---/ && ($checking_volumegroups = 1);
	if ($checking_volumegroups) {
		/Name:/ && do {
			($dummy, $name) = split;
		};
		/Status:/ && do {
			($dummy, $status) = split;
			if ($status ne 'Optimal' || $debug) {
				$result = $WARNING;
				push @errors, sprintf "Volume Group %s: %s\n", $name, $status;
			};
		};
	};

	/^STANDARD VOLUMES---/ && ($checking_volumes = 1);
	if ($checking_volumes) {
		/Volume name:/ && do {
			($dummy, $dummy, $name) = split;
		};
		/Volume status:/ && do {
			($dummy, $dummy, $status) = split;
			if ($status ne 'Optimal' || $debug) {
				$result = $WARNING;
				push @errors, sprintf "Volume %s: %s\n", $name, $status;
			};
		};
	};

	/^DRIVES---/ && ($checking_drives = 1);
	if ($checking_drives) {
		/Drive at / && do {
			($dummy, $name) = split(/ at /, $_);
		};
		/Status:/ && do {
			($dummy, $status) = split;
			if ($status ne 'Optimal' || $debug) {
				$result = $WARNING;
				push @errors, sprintf "Drive %s: %s\n", $name, $status;
			};
		};
	}
	
	/^DRIVE CHANNELS---/ && ($checking_channels = 1);
	if ($checking_channels) {
		/DRIVE CHANNEL/ && do {
			($dummy, $dummy, $name) = split;
		};
		/Status:/ && do {
			($dummy, $status) = split;
			if ($status ne 'Optimal' || $debug) {
				$result = $WARNING;
				push @errors, sprintf "Channel %s: %s\n", $name, $status;
			};
		};
	}

	/TRAYS---/ && ($checking_trays = 1);
	if ($checking_trays) {
		/Battery status:/ && do {
			($dummy, $dummy, $status) = split;
			if (($status ne 'Optimal' && $status ne 'Charging') || $debug) {
				$result = $WARNING;
				push @errors, sprintf "Tray Battery: %s\n", $status;
			};
		};
		/SFP status:/ && do {
			($dummy, $dummy, $status) = split;
			if ($status ne 'Optimal' || $debug) {
				$result = $WARNING;
				push @errors, sprintf "Tray SFP: %s\n", $status;
			};
		};
		/Power-fan canister.*status:/ && do {
			($dummy, $dummy, $dummy, $dummy, $status) = split;
			if ($status ne 'Optimal' || $debug) {
				$result = $WARNING;
				push @errors, sprintf "Power-Fan canister: %s\n", $status;
			};
		};
	}
}

out:
printf "%s %s\n", $controller, $states[$result];
print @errors;
exit $result;
