#!/usr/bin/perl use strict; use warnings; use English; use Getopt::Long; # check status of various hardware devices (fans, temp, dimms, powersupply) # requires hpasmcli # Copyright (c) 2009 Stephen Gran # Copyright (c) 2009,2010,2012 Peter Palfrader # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in 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: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # 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 THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. my $command = < \&do_dimm, 'SHOW FANS' => \&do_fans, 'SHOW POWERSUPPLY' => \&do_powersupply, 'SHOW TEMP' => \&do_temp, ); my $params = {}; my $USAGE = "PROGRAM_NAME: Usage: $PROGRAM_NAME [--help] [--ps-no-redundant] [--fan-no-redundant] [--fan-high] [--dimm-na] [--fan-ignore-not-present] [--ignore-failed= [--ignore-failed=]n"; Getopt::Long::config('bundling'); if (!GetOptions ($params, '--help', '--ps-no-redundant', '--fan-no-redundant', '--fan-high', '--dimm-na', '--fan-ignore-not-present', '--ignore-failed=s@', )) { die ("$USAGE"); }; if ($params->{'help'}) { print "$USAGE"; print "Checks hp hardware health.\n"; exit (0); }; my $prompt = "hpasmcli>"; my $exit_status = 0; my $ret = ''; my %ignore_failed = map {$_ => 1} @{$params->{'ignore-failed'}}; sub do_dimm { my @output = @_; my $dimm_num = my $status = my $return = my $message = ''; my $in_block = my $header_seen = my $num_dimms = 0; for my $line (@output) { chomp $line; unless ($header_seen) { next until ($line eq "$prompt SHOW DIMM"); $header_seen++; next; } if ($line =~ /(^\s*$|-----)/) { if ($in_block) { unless (($status eq 'Ok') || ($params->{'dimm-na'} && $status eq 'N/A')) { my $what = sprintf("DIMM%d", $dimm_num); $message = sprintf("%s: %s ", $what, $status); $exit_status |= 2 unless (exists $ignore_failed{$what}); } $return .= $message if ($message); $message = $status = ''; } else { $in_block++; } } if ($line =~ /^Module #:\s+(\d)/) { $dimm_num = $1; $num_dimms++; } elsif ($line =~ /Status:\s+(\S+(\s*(.*)?))/) { $status = $1; } elsif ($line =~ /$prompt/) { last; } } if ($return eq '') { return "DIMMS OK ($num_dimms) "; } else { return $return; } } sub do_fans { my @output = @_; my $fan_num = my $status = my $present = my $return = my $message = ''; my $header_seen = my $num_fans = 0; for my $line (@output) { chomp $line; unless ($header_seen) { next until ($line eq "$prompt SHOW FANS"); $header_seen++; next; } if ($line =~ /^#(\d+)/) { if ($num_fans) { $return .= $message if ($message); $message = ''; } $fan_num = $1; $num_fans++; my @line = split /\s+/, $line; if ($line[1] eq 'VIRTUAL') { # blade, etc $message = 'FAN1: (virtual) OK '; last; } my $what = sprintf("FAN%d", $fan_num); if ($line[2] ne 'Yes') { $message = sprintf("%s: status=%s ", $what, $line[2]); $exit_status |= 2 unless ($params->{'fan-ignore-not-present'} || (exists $ignore_failed{$what})); } elsif ($line[3] ne 'NORMAL') { $message = sprintf("%s: speed=%s ", $what, $line[3]); $exit_status |= 1 unless ($line[3] eq 'HIGH' && $params->{'fan-high'} || (exists $ignore_failed{$what})); } elsif ($line[5] ne 'Yes') { $message = sprintf("%s: redundant=%s ", $what, $line[5]); $exit_status |= 1 unless ($params->{'fan-no-redundant'} || (exists $ignore_failed{$what})); } } elsif ($line =~ /($prompt|^\s*$)/) { last; } } $return .= $message if ($message); if ($return eq '') { return "FANS OK ($num_fans) "; } else { return $return; } } sub do_powersupply { my @output = @_; my $ps_num = '?'; my $return = my $message = ''; my $header_seen = my $num_ps = 0; for my $line (@output) { chomp $line; unless ($header_seen) { next until ($line eq "$prompt SHOW POWERSUPPLY"); $header_seen++; next; } my $what = sprintf("PS%s", $ps_num); if ($line =~ /^Power supply #(\d+)/) { if ($num_ps) { $return .= $message if ($message); $message = ''; } $ps_num = $1; $num_ps++; } elsif ($line =~ /\s+Present\s*:\s+(.*)/) { my $present = $1; if ($present ne 'Yes') { $message = sprintf("%s missing ", $what); $exit_status |= 1 unless (exists $ignore_failed{$what}); } } elsif ($line =~ /\s+Condition\s*:\s+(.*)/) { my $status = $1; if ($status ne 'Ok') { $message = sprintf("%s: %s ", $what, $status); $exit_status |= 2 unless (exists $ignore_failed{$what}); } } elsif ($line =~ /\s+Redundant\s*:\s+(.*)/) { my $redundant = $1; if ($redundant ne 'Yes') { $message = sprintf("%s not redundant ", $what); $exit_status |= 1 unless ($params->{'ps-no-redundant'} || (exists $ignore_failed{$what})); } } elsif ($line =~ /($prompt|^\s*$)/) { last; } } $return .= $message if ($message); if ($return eq '') { return "POWER OK ($num_ps) "; } else { return $return; } } sub do_temp { my @output = @_; my $temp_num = my $return = my $message = ''; my $header_seen = my $num_temp = 0; for my $line (@output) { chomp $line; unless ($header_seen) { next until ($line eq "$prompt SHOW TEMP"); $header_seen++; next; } if ($line =~ /^#(\d+)/) { if ($num_temp) { $return .= $message if ($message); $message = ''; } $temp_num = $1; my @line = split /\s+/, $line; my $zone = $line[1]; my $current_temp = $line[2]; my $threshold = $line[3]; $current_temp =~ s/(.*)C.*/$1/; $threshold =~ s/(.*)C.*/$1/; next if ($threshold eq '-'); $num_temp++; my $what = sprintf("TEMP zone=%s", $zone); if ($current_temp ne '-') { my $off = $threshold - $current_temp; if ($off <= 0) { $message = sprintf("%s %sC/%sC ", $what, $current_temp, $threshold); $exit_status |= 2 unless (exists $ignore_failed{$what}); } elsif ($off < ($threshold/10)) { $message = sprintf("%s %sC/%sC ", $what, $current_temp, $threshold); $exit_status |= 1 unless (exists $ignore_failed{$what}); } } } elsif ($line =~ /($prompt|^\s*$)/) { last; } } $return .= $message if ($message); if ($return eq '') { return "TEMP OK ($num_temp) "; } else { return $return; } } my @output = `echo "$command"|sudo hpasmcli 2>&1`; if (($? >> 8) != 0) { print "UNKNOWN: Can't exec hpasmcli: @output\n"; exit 3; } for my $line (@output) { chomp $line; for my $check (sort keys %callbacks) { if ($line eq "$prompt $check") { $ret .= &{$callbacks{$check}}(@output); } } } if ($exit_status & 2) { print "CRITICAL: $ret\n"; exit 2; } elsif ($exit_status & 1) { print "WARNING: $ret\n"; exit 1; } else { print "OK: $ret\n"; exit 0; }