#! /usr/bin/perl -w

# check_tw_cli Copyright (C) 2006 Stephan Lauffer <lauffer@ph-freiburg.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# you should have received a copy of the GNU General Public License
# along with this program (or with Nagios);  if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA

use strict;
use Getopt::Long;
use vars qw($PROGNAME);
use lib "/usr/lib/nagios/plugins";
use utils qw ($TIMEOUT %ERRORS &print_revision &support);

sub print_help ();
sub print_usage ();

my (
	# nagios plugin default options...
	$opt_h,
	$opt_V,
	$opt_t,
	$verbose,
	
	# check_tw_cli options...
	$opt_d,
	$opt_r,
	$opt_U,
	
	# others...
	$result,
	$message,
	$version,
	$author,

	# tw_cli related...
	$tested_cli_version,
	$tested_api_version,
	$cli_version,
	$api_version,
	$tw_cli_bin,
	$tw_cli_exec,
	$tw_cli_version,
	$tw_cli_unit,
	$tw_cli_unittype,
	$tw_cli_status,
	$tw_cli_cmpl,
	$tw_cli_port,
	$tw_cli_cmd,
	$tw_cli_critical_v1,
	$tw_cli_critical_v2,
);

###########
#
# configuration

# PLEASE CHECK $tw_cli_bin AND $tw_cli_exec for your requirements! Any other variables should not be changed.
#
$tw_cli_bin		= '/usr/local/sbin/tw_cli';
$tw_cli_exec		= "/usr/bin/sudo";

$PROGNAME		= "check_tw_cli";
$version		= "0.3.1";
$author			= 'Copyright (C) 2006 Stephan Lauffer <lauffer@ph-freiburg.de>';

$opt_r			= "";
$opt_U			= "";
$opt_d			= "";
$message		= "";
$result			= "";
$tw_cli_unit		= "";
$tw_cli_unittype	= "";
$tw_cli_status		= "";
$tw_cli_cmpl		= "";
$tw_cli_port 		= "";
$tw_cli_critical_v1	= 'CORRUPT|INCOMPLETE|';
$tw_cli_critical_v2	= 'CORRUPT|INOPERABLE';

$tested_cli_version	= '2\.00\..*';	# please use a regex syntax here. this test may be removed in the future
$tested_api_version	= '2\.00\..*';	# please use a regex syntax here. this test may be removed in the future
$tw_cli_version		= 'UNKNOWN';
$cli_version		= 'UNKNOWN';
$api_version		= 'UNKNOWN';

#
############

Getopt::Long::Configure('bundling');
GetOptions(
	"V"	=> \$opt_V,	"version"			=> \$opt_V,
	"v"	=> \$verbose,	"verbose"			=> \$verbose,
	"h"	=> \$opt_h,	"help"				=> \$opt_h,
	"d"	=> \$opt_d,	"detailed"			=> \$opt_d,
	"r=f"	=> \$opt_r,	"raid-controller-number=f"	=> \$opt_r,
	"U=f"	=> \$opt_U,	"unit-number=f"			=> \$opt_U,
	);

############
# some checks...
#
# note:
# first "bad" return code wins although further test will follow

if ($opt_V) {
	print_revision($PROGNAME, "$version $author");
	exit $ERRORS{'OK'};
}

if ($opt_h) {
	print_help();
	exit $ERRORS{'OK'};
}

if ($opt_r eq "") {
	$message .= "No raid controller number given\n";
	$result or $result = 'UNKNOWN';
} elsif ($opt_r !~ /^\d$/) {
	$message .= "$opt_r ist not a valid controller number\n";
	$result or $result = 'UNKNOWN';
}

if ($opt_U eq "") {
	$message .= "No unit number given\n";
	$result or $result = 'UNKNOWN';
} elsif ($opt_U !~ /^\d$/) {
	$message .= "$opt_r ist not a valid unit number\n";
	$result or $result = 'UNKNOWN';
}

if ($tw_cli_exec and ! -f $tw_cli_exec) {
	$message .= "$tw_cli_exec missing!\n";
	$result or $result = 'UNKNOWN';
}

if (! -f $tw_cli_bin) {
	$message .= "$tw_cli_bin missing!\n";
	$result or $result = 'UNKNOWN';
}

$message and print $message;
$result and exit $ERRORS{$result};
#
############

############
# main

# start timeoutcheck

$SIG{'ALRM'} = sub {
	print ("ERROR: No response from check_tw_cli (alarm)\n");
	exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);

# check tw_cli/cli/api version

$verbose and print "Testing tw_cli version...\n";

open (TW_CLI, "$tw_cli_exec $tw_cli_bin show ver 2>\&1|") or exit $ERRORS{"UNKNOWN"};

while (<TW_CLI>) {
	chomp;

	$verbose and print "$_\n";

	# someone may have problem with his 3ware-tool (:

	/^opendir: No such file or directory/ and last;	

	# "hack" to detect if this is a tw_cli v1...:

	/^Unknown command 'show'/ and $tw_cli_version = "v1" and last;

	if (/^CLI Version = ([\d+\.]+)/) {
		$cli_version = $1;
		if ($cli_version !~ /^$tested_cli_version/) {
			$message .= "CLI Version $cli_version not supported by $PROGNAME $version\n";
			$result or $result = 'UNKNOWN';
		} else {
			$tw_cli_version = "v2";
		}
	}
	if (/^API Version = ([\d+\.]+)/) {
		$api_version = $1;
		if ($api_version !~ /^$tested_api_version/) {
			$message .= "API Version $1 not supported by $PROGNAME $version\n";
			$result or $result = 'UNKNOWN';
		}
	}
}
close TW_CLI;
$verbose and print "Test finished - CLI version: $cli_version, API versino: $api_version, tw_cli_version: $tw_cli_version\n\n";

# exit if tw_cli is not "known", does not work with this plugin

if ($cli_version eq "UNKNOWN" or $api_version eq "UNKNOWN" or $tw_cli_version eq "UNKNOWN") {
	$tw_cli_version eq "UNKNOWN" and
		$message = "Warning: your tw_cli does not work. See Q10166, Q11928 or other articles in the 3ware knowledge base.\n";
	$message .= "tw_cli, API/CLI Version not known\n";
	$result or $result = 'UNKNOWN';
	exit $ERRORS{$result};
}

# go ahead with the raid status tests...

$result	= "UNKNOWN";	# set state to unknow until we know a bit more...

# prepare the tw_cli command

if ($tw_cli_version eq "v1") {
	$tw_cli_cmd = "/c${opt_r}/u${opt_U} show";
} elsif ($tw_cli_version eq "v2") {
	$tw_cli_cmd = "info c${opt_r} u${opt_U}";
} else {
	print "tw_cli_cmd not know for tw_cli_version $tw_cli_version!\n";
	exit $ERRORS{$result};
}

# execute tw_cli

$verbose and print "Reading raid status (\"$tw_cli_exec $tw_cli_bin $tw_cli_cmd\")\n";

open (TW_CLI, "$tw_cli_exec $tw_cli_bin $tw_cli_cmd|") or exit $ERRORS{"UNKNOWN"};
while (<TW_CLI>) {

	chomp;

	$verbose and print "$_\n";
	
	# checking v1 reports...
	# note: the report results from tw_cli v1 are not well know by this plugin (please test && send reports)

	# any not "OK" status causes a warning, every $tw_cli_critical_v2 match causes a CRITICAL check_tw_cli return

	if ($tw_cli_version eq "v1") {

		my $hot=0;

		/^Controller\s+$opt_r,\s+Unit\s+$opt_U/ and $hot = 1;

		$hot and /^Status:\s+(.{,12})/		and $tw_cli_status	= $1;	# sorry, I don't know all the return codes... 
		$hot and /^Unit Type:\s+(.{,12})/	and $tw_cli_unittype	= $1;	# sorry, I don't know...
		
		if ($tw_cli_status and $tw_cli_unittype) {

			$tw_cli_status ne "OK" and $result = "WARNING";

			if ($tw_cli_status =~ /^($tw_cli_critical_v1)/) {
				$result ='CRITICAL';
			}
			
			$message = "RAID Status on c$opt_r $tw_cli_unittype: $tw_cli_status";

			last;
		}

	# checking v2 reports...
	# note: the report results from tw_cli v2 are not well know by this plugin (please test && send reports)
		
	# any not "OK" status causes a warning, every $tw_cli_critical_v2 match causes a CRITICAL check_tw_cli return

	} elsif ($tw_cli_version eq "v2") {
		# Unit UnitType Status %Cmpl Port
		if (/^(u[\d\-]+)\s+([\w\-]+)\s+([\w\-]+)\s+([\w\-]+)\s+([\w\-]+)/) {

			$tw_cli_unit		= $1;
			$tw_cli_unittype	= $2;
			$tw_cli_status		= $3;
			$tw_cli_cmpl		= $4;
			$tw_cli_port		= $5;
	
			$tw_cli_unittype =~ /^RAID/ and $result = $tw_cli_status;
			$tw_cli_status ne "OK" and $result = "WARNING";

			if ($tw_cli_status =~ /^($tw_cli_critical_v2)/) {
				$result ='CRITICAL';
			}

			$tw_cli_unittype =~ /^RAID/ and $message = "RAID Status on c$opt_r $tw_cli_unit: $tw_cli_status";
			if ($opt_d) {
				$message .= " - UnitType: $tw_cli_unittype, Status: $tw_cli_status, ";
				$tw_cli_cmpl ne "-" and $message .= "\%Cmpl $tw_cli_cmpl, ";
				$tw_cli_port ne "-" and $message .= "Port: $tw_cli_port, ";
			}

		} else {
#			$verbose and print "unknown tw_cli result:$_\n";
		}
		$message =~ s/, $//;
	}
}
close TW_CLI;

# disable alarm	
alarm(0);

# return message and exit with returncode
print "$message\n";
exit $ERRORS{$result};

#
############

############
# subs

sub print_usage () {
	print "Usage:\n";
	print "  $PROGNAME [[-r <number>] [-U <number>]] [-v | --verbose] [ -d | --detailed]\n";
	print "  $PROGNAME [-h | --help]\n";
	print "  $PROGNAME [-V | --version]\n";
}

sub print_help () {
	print_revision($PROGNAME, "$version");
	print "$author\n\n";
	print "$PROGNAME was written to read the status of a 3ware RAID on localhost.\n\n";
	print_usage();
	print "\n";
	print "  Example: ./check_tw_cli -r 0 -U 0\n";
	print "\n";
	support();
}
#
############
# eof
