Search
j0ke.net Open Build Service
>
Projects
>
home:netmax
>
nagios-plugins-lsi
> check_megaraid_sas
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File check_megaraid_sas of Package nagios-plugins-lsi (Revision 9)
Currently displaying revision
9
,
show latest
#!/usr/bin/perl -w # check_megaraid_sas Nagios plugin # Copyright (C) 2007 Jonathan Delgado, delgado@molbio.mgh.harvard.edu # # 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; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # # Nagios plugin to monitor the status of volumes attached to a LSI Megaraid SAS # controller, such as the Dell PERC5/i and PERC5/e. If you have any hotspares # attached to the controller, you can specify the number you should expect to # find with the '-s' flag. # # The paths for the Nagios plugins lib and MegaCli may need to me changed. # # Code for correct RAID level reporting contributed by Frode Nordahl, 2009/01/12. # Some other code contributed by Morty Abzug, 2015-05-20 # # $Author: delgado $ # $Revision: #12 $ $Date: 2010/10/18 $ use strict; use Getopt::Long; use lib qw(/usr/lib/nagios/plugins /usr/lib64/nagios/plugins); # possible pathes to your Nagios plugins and utils.pm use utils qw(%ERRORS); my $megaclibin = '/usr/sbin/MegaCli'; # the full path to your MegaCli binary my $megacli = "$megaclibin"; # how we actually call MegaCli my $megapostopt = '-NoLog'; # additional options to call at the end of MegaCli arguments my ($adapters); my $hotspares = 0; my $hotsparecount = 0; my $pdbad = 0; my $pdcount = 0; my $mediaerrors = 0; my $mediaallow = 0; my $consistency_check_is_ok = 0; my $missing_is_ok = 0; my $no_battery_is_ok = 0; my $prederrors = 0; my $predallow = 0; my $othererrors = 0; my $otherallow = 0; my $result = ''; my $status = 'OK'; my $sudo; my $checkbbu = 0; my $bbu_charge_no_warning = 0; my $check_cache; my $do_help; # handle options Getopt::Long::Configure("bundling"); GetOptions( "b|bbu_check" => \$checkbbu, "B|bbu_charge_no_warning" => \$bbu_charge_no_warning, "c|cache_check" => \$check_cache, "h|help" => \$do_help, "m|media_allow=i" => \$mediaallow, "consistency_check_is_ok" => \$consistency_check_is_ok, "missing_is_ok" => \$missing_is_ok, "no_battery_is_ok" => \$no_battery_is_ok, "o|other_allow=i" => \$otherallow, "p|pred_allow=i" => \$predallow, "s|hotspares=i" => \$hotspares, "sudo" => \$sudo, ); if ( $do_help ) { print "Usage: $0 [-s number] [-m number] [-o number]\n"; print " -b check Battery Back Up status\n"; print " -B battery back up charging state is not a warning\n"; print " -c check that current cache policy matches default policy\n"; print " -m is the number of media errors to ignore\n"; print " --consistency_check_is_ok consistency checks are OK\n"; print " --missing_is_ok test returns OK if MegaCli is not present\n"; print " --no_battery_is_ok lack of a battery is not a problem\n"; print " -p is the predictive error count to ignore\n"; print " -o is the number of other disk errors to ignore\n"; print " -s is how many hotspares are attached to the controller\n"; print " --sudo should sudo be enabled\n"; exit; } sub max_state ($$) { my ($current, $compare) = @_; if (($compare eq 'CRITICAL') || ($current eq 'CRITICAL')) { return 'CRITICAL'; } elsif ($compare eq 'OK') { return $current; } elsif ($compare eq 'WARNING') { return 'WARNING'; } elsif (($compare eq 'UNKNOWN') && ($current eq 'OK')) { return 'UNKNOWN'; } else { return $current; } } sub exitreport ($$) { my ($status, $message) = @_; print STDOUT "$status: $message\n"; exit $ERRORS{$status}; } # Some sanity checks that you actually have something where you think MegaCli is if (! -e $megaclibin) { if ($missing_is_ok) { exitreport($status, "$megaclibin is not present, missing_is_ok set") } else { exitreport('UNKNOWN',"error: $megaclibin does not exist"); } } $megacli="sudo $megacli" if $sudo; # Get the number of RAID controllers we have open (ADPCOUNT, "$megacli -adpCount $megapostopt |") || exitreport('UNKNOWN',"error: Could not execute $megacli -adpCount $megapostopt"); while (<ADPCOUNT>) { if ( m/Controller Count:\s*(\d+)/ ) { $adapters = $1; last; } } close ADPCOUNT; exitreport('UNKNOWN',"error: unable to get controller count") if !defined $adapters; ADAPTER: for ( my $adp = 0; $adp < $adapters; $adp++ ) { $result .= "$adp:"; # Get the Battery Back Up state for this adapter my ($bbustate); if ($checkbbu) { open (BBUGETSTATUS, "$megacli -AdpBbuCmd -GetBbuStatus -a$adp $megapostopt |") || exitreport('UNKNOWN', "error: Could not execute $megacli -AdpBbuCmd -GetBbuStatus -a$adp $megapostopt"); my ($bbucharging, $bbufullycharged, $bburelativecharge, $bbuexitcode); my ($batterystate, $batteryreplacement, $issohgood); while (<BBUGETSTATUS>) { # Charging Status if ( m/Charging Status\s*:\s*(\w+)/i ) { $bbucharging = $1; } elsif ( m/Battery State\s*:\s*(\w+.*)/i) { # sometimes contains a space $batterystate = $1; } elsif ( m/Fully Charged\s*:\s*(\w+)/i ) { $bbufullycharged = $1; } elsif ( m/Relative State of Charge\s*:\s*(\w+)/i ) { $bburelativecharge = $1; } elsif ( m/Exit Code\s*:\s*(\w+)/i ) { $bbuexitcode = $1; } elsif ( m/^\s*Battery Replacement required\s*:\s(\w+)\s*$/i) { $batteryreplacement = $1; } elsif ( m/^\s*isSOHGood\s*:\s*(\w+)\s*$/i) { $issohgood = $1; } } close BBUGETSTATUS; # Determine the BBU state if ( !defined $bbuexitcode || $bbuexitcode ne '0x00' ) { if (!$no_battery_is_ok) { $bbustate = 'NOT FOUND'; $status = max_state($status, 'CRITICAL'); } else { $bbustate = 'not found which could be ok'; } } elsif ( lc $batteryreplacement ne 'no' ) { $bbustate = 'battery needs replacing'; $status = max_state($status, 'CRITICAL'); } elsif ( defined $issohgood && lc $issohgood ne 'yes' ) { $bbustate = 'battery SOH is not good'; $status = max_state($status, 'CRITICAL'); } elsif ( $bbucharging ne 'None' && !$bbu_charge_no_warning) { $bbustate = 'Charging (' . $bburelativecharge . '%)'; $status = max_state($status, 'WARNING'); } elsif ( defined $bbufullycharged && $bbufullycharged ne 'Yes' && !$bbu_charge_no_warning) { # some adapters don't report on "Fully Charged", so # it's OK if it's not defined. $bbustate = 'Not Charging (' . $bburelativecharge . '%)'; $status = max_state($status, 'WARNING'); } elsif ( defined $batterystate && $batterystate ne 'Optimal' && $batterystate ne 'Operational') { $bbustate = $batterystate; $status = max_state($status, 'WARNING'); } else { $bbustate = 'Charged (' . $bburelativecharge . '%)'; } $result .= "BBU $bbustate:"; } # Get the number of logical drives on this adapter open (LDGETNUM, "$megacli -LdGetNum -a$adp $megapostopt |") || exitreport('UNKNOWN', "error: Could not execute $megacli -LdGetNum -a$adp $megapostopt"); my ($ldnum); while (<LDGETNUM>) { if ( m/Number of Virtual drives configured on adapter \d:\s*(\d+)/i ) { $ldnum = $1; last; } } close LDGETNUM; LDISK: for ( my $ld = 0; $ld < $ldnum; $ld++ ) { # Get info on this particular logical drive open (LDINFO, "$megacli -LdInfo -L$ld -a$adp $megapostopt |") || exitreport('UNKNOWN', "error: Could not execute $megacli -LdInfo -L$ld -a$adp $megapostopt "); my $consistency_output = ''; my ($size, $unit, $raidlevel, $ldpdcount, $state, $spandepth, $consistency_percent, $consistency_minutes); my $current_cache_policy; my $default_cache_policy; while (<LDINFO>) { if ( m/^Size\s*:\s*((\d+\.?\d*)\s*(MB|GB|TB))/ ) { $size = $2; $unit = $3; # Adjust MB to GB if that's what we got if ( $unit eq 'MB' ) { $size = sprintf( "%.0f", ($size / 1024) ); $unit= 'GB'; } } elsif ( m/State\s*:\s*(\w+)/ ) { $state = $1; if ( $state ne 'Optimal' ) { $status = max_state($status, 'CRITICAL'); } } elsif ( m/Number Of Drives\s*(per span\s*)?:\s*(\d+)/ ) { $ldpdcount = $2; } elsif ( m/Span Depth\s*:\s*(\d+)/ ) { $spandepth = $1; } elsif ( m/^\s*Default Cache Policy\s*:\s*(.*)/ ) { $default_cache_policy=$1; } elsif ( m/^\s*Current Cache Policy\s*:\s*(.*)/ ) { $current_cache_policy=$1; } elsif ( m/RAID Level\s*: Primary-(\d)/ ) { $raidlevel = $1; } elsif ( m/\s+Check Consistency\s+:\s+Completed\s+(\d+)%,\s+Taken\s+(\d+)\s+min/ ) { $consistency_percent = $1; $consistency_minutes = $2; } } close LDINFO; # Report correct RAID-level and number of drives in case of Span configurations if ($ldpdcount && $spandepth > 1) { $ldpdcount = $ldpdcount * $spandepth; if ($raidlevel < 10) { $raidlevel = $raidlevel . "0"; } } if ($consistency_percent) { $status = max_state($status, 'WARNING') if !$consistency_check_is_ok; $consistency_output = "CC ${consistency_percent}% ${consistency_minutes}m:"; } if ($check_cache) { if (defined($current_cache_policy) && defined($default_cache_policy) && $default_cache_policy eq $current_cache_policy) { $result .= "cache policy $current_cache_policy:"; } elsif (!defined($current_cache_policy)) { $result .= "cache policy UNKNOWN:"; $status = max_state($status, 'UNKNOWN'); } elsif (!defined($default_cache_policy)) { $result .= "cache policy $current_cache_policy, default UNKNOWN:"; $status = max_state($status, 'UNKNOWN'); } else { $result .= "cache policy $current_cache_policy, SHOULD BE $default_cache_policy:"; $status = max_state($status, 'WARNING'); } } $result .= "$ld:RAID-$raidlevel:$ldpdcount drives:$size$unit:$consistency_output$state "; } #LDISK close LDINFO; # Get info on physical disks for this adapter open (PDLIST, "$megacli -PdList -a$adp $megapostopt |") || exitreport('UNKNOWN', "error: Could not execute $megacli -PdList -a$adp $megapostopt "); my ($slotnumber,$fwstate); PDISKS: while (<PDLIST>) { if ( m/Slot Number\s*:\s*(\d+)/ ) { $slotnumber = $1; $pdcount++; } elsif ( m/(\w+) Error Count\s*:\s*(\d+)/ ) { if ( $1 eq 'Media') { $mediaerrors += $2; } else { $othererrors += $2; } } elsif ( m/Predictive Failure Count\s*:\s*(\d+)/ ) { $prederrors += $1; } elsif ( m/Firmware state\s*:\s*(\w+)/ ) { $fwstate = $1; if ( $fwstate eq 'Hotspare' ) { $hotsparecount++; } elsif ( $fwstate eq 'Online' ) { # Do nothing } elsif ( $fwstate eq 'JBOD' ) { # Do nothing } elsif ( $fwstate eq 'Unconfigured' ) { # A drive not in anything, or a non drive device $pdcount--; } elsif ( $slotnumber != 255 ) { $pdbad++; $status = max_state($status, 'CRITICAL'); } } } #PDISKS close PDLIST; } $result .= "Drives:$pdcount "; # Any bad disks? if ( $pdbad ) { $result .= "$pdbad Bad Drives "; } my $errorcount = $mediaerrors + $prederrors + $othererrors; # Were there any errors? if ( $errorcount ) { $result .= "($errorcount Errors: $mediaerrors media, $prederrors predictive, $othererrors other) "; if ( ( $mediaerrors > $mediaallow ) || ( $prederrors > $predallow ) || ( $othererrors > $otherallow ) ) { $status = max_state($status, 'WARNING'); } } # Do we have as many hotspares as expected (if any) if ( $hotspares ) { if ( $hotsparecount < $hotspares ) { $status = max_state($status, 'WARNING'); $result .= "Hotspare(s):$hotsparecount (of $hotspares)"; } else { $result .= "Hotspare(s):$hotsparecount"; } } exitreport($status, $result);