#!/usr/bin/perl -w # # check_tw_cli Copyright (C) 2012 Stephan Lauffer # # 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_vim, $tw_cli_port, $tw_cli_stripe, $tw_cli_size, $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.7"; $author = 'Copyright (C) 2012 Stephan Lauffer '; $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.*'; # 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_exec 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 ntp server (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 () { 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 () { 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") { if (/^u/) { # get/split tw_cli output ($tw_cli_unit, $tw_cli_unittype, $tw_cli_status, $tw_cli_cmpl, $tw_cli_vim, $tw_cli_port, $tw_cli_stripe, $tw_cli_size) = split (/\s+/, $_); # right now don't know how to interpret status for volumes... $tw_cli_unittype eq "Volume" and next; # get status of UnitType RAID* or SPARE or DISK... # result may not get "OK" unsless any state is ok. result may not get warning, if something is critical... if ($tw_cli_unittype =~ /^(RAID)|(SPARE)|(DISK)/ and $result ne 'CRITICAL') { if ($result ne "WARNING") { $result = $tw_cli_status; } } # if any UnitType (Disk, Raid, Volum...) is not "OK", we are on WARNING state... if ($tw_cli_status ne "OK" and $result ne 'CRITICAL') { $result = "WARNING"; } # compare the stat for our critival level... if ($tw_cli_status =~ /^($tw_cli_critical_v2)/) { $result = 'CRITICAL'; } # skid information if we do not need to show more detailed informations # (but do not skip if there is a line else than ok... if (!$opt_d and ($tw_cli_unit =~ /\-/)) { if ($tw_cli_status ne "OK") { # hm... } else { next; } } # default message string: $tw_cli_unittype =~ /^(RAID)|(SPARE)|(DISK)/ and $message .= " | $tw_cli_unittype Unit $tw_cli_unit: $tw_cli_status"; #$tw_cli_unittype =~ /^(RAID)|(SPARE)|(DISK)/ and $message .= " | $tw_cli_unittype Unit $tw_cli_unit: $result"; # further informations... if ($tw_cli_status ne "OK" and $tw_cli_unittype eq "DISK") { $message .= " (Port $tw_cli_port)"; } if ($opt_d and $tw_cli_status =~ /REBUILDING|INITIALIZING/ ) { my $percent = $tw_cli_cmpl=~/\d+/ ? $tw_cli_cmpl : $tw_cli_vim; $percent !~ /\%$/ and $percent .= '%'; $message .= " Cmpl " . $percent; } } else { # $verbose and print "unknown tw_cli result:$_\n"; } } } close TW_CLI; $message =~ s/^\s+\|* //; $message =~ s/,\s*$//; $message = "Raid Status on Ctrl $opt_r: " . $message; # 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 ] [-U ]] [-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