work around virtual fans on things like blades
[mirror/dsa-nagios.git] / dsa-nagios-checks / checks / dsa-check-hpasm
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 # check status of various hardware devices (fans, temp, dimms, powersupply)
7 # requires hpasmcli
8
9 # Copyright (c) 2009 Stephen Gran <steve@lobefin.net>
10 #
11 # Permission is hereby granted, free of charge, to any person obtaining
12 # a copy of this software and associated documentation files (the
13 # "Software"), to deal in the Software without restriction, including
14 # without limitation the rights to use, copy, modify, merge, publish,
15 # distribute, sublicense, and/or sell copies of the Software, and to
16 # permit persons to whom the Software is furnished to do so, subject to
17 # the following conditions:
18 #
19 # The above copyright notice and this permission notice shall be
20 # included in all copies or substantial portions of the Software.
21 #
22 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 my $command = <<EOF;
31 SHOW DIMM
32 SHOW FANS
33 SHOW POWERSUPPLY
34 SHOW TEMP
35 QUIT
36 EOF
37
38 my %callbacks = (
39   'SHOW DIMM'        => \&do_dimm,
40   'SHOW FANS'        => \&do_fans,
41   'SHOW POWERSUPPLY' => \&do_powersupply,
42   'SHOW TEMP'        => \&do_temp,
43 );
44
45 my $prompt = "hpasmcli>";
46 my $exit_status = 0;
47 my $ret = '';
48
49 sub do_dimm {
50   my @output = @_;
51   my $dimm_num = my $status = my $return = my $message = '';
52   my $in_block = my $header_seen = my $num_dimms = 0;
53
54   for my $line (@output) {
55     chomp $line;
56     unless ($header_seen) {
57       next until ($line eq "$prompt SHOW DIMM");
58       $header_seen++;
59       next;
60     }
61
62     if ($line =~ /(^\s*$|-----)/) {
63       if ($in_block) {
64         if ($status ne 'Ok') {
65           $message = sprintf("DIMM%d: %s ", $dimm_num, $status);
66           $exit_status |= 2;
67         }
68         $return .= $message if ($message);
69         $message = $status = '';
70       } else {
71         $in_block++;
72       }
73     }
74
75     if ($line =~ /^Module #:\s+(\d)/) {
76       $dimm_num = $1;
77       $num_dimms++;
78     } elsif ($line =~ /Status:\s+(\S+(\s*(.*)?))/) {
79       $status = $1;
80     } elsif ($line =~ /$prompt/) {
81       last;
82     }
83   }
84
85   if ($return eq '') {
86     return "DIMMS OK ($num_dimms) ";
87   } else {
88     return $return;
89   }
90 }
91
92 sub do_fans {
93   my @output = @_;
94   my $fan_num = my $status = my $present = my $return = my $message = '';
95   my $header_seen = my $num_fans = 0;
96
97   for my $line (@output) {
98     chomp $line;
99     unless ($header_seen) {
100       next until ($line eq "$prompt SHOW FANS");
101       $header_seen++;
102       next;
103     }
104
105     if ($line =~ /^#(\d+)/) {
106       if ($num_fans) {
107         $return .= $message if ($message);
108         $message = '';
109       }
110
111       $fan_num = $1;
112       $num_fans++;
113       my @line = split /\s+/, $line;
114
115       if ($line[1] eq 'VIRTUAL') { # blade, etc
116         $message = 'FAN1: (virtual) OK ';
117         last;
118       }
119
120       if ($line[2] ne 'Yes') {
121         $message = sprintf("FAN%d: status=%s ", $fan_num, $line[2]);
122         $exit_status |= 2;
123       } elsif ($line[3] ne 'NORMAL') {
124         $message = sprintf("FAN%d: speed=%s ", $fan_num, $line[3]);
125         $exit_status |= 1;
126       } elsif ($line[5] ne 'Yes') {
127         $message = sprintf("FAN%d: redundant=%s ",$fan_num, $line[5]);
128         $exit_status |= 1;
129       }
130     } elsif ($line =~ /($prompt|^\s*$)/) {
131       last;
132     }
133   }
134   $return .= $message if ($message);
135
136   if ($return eq '') {
137     return "FANS OK ($num_fans) ";
138   } else {
139     return $return;
140   }
141 }
142
143 sub do_powersupply {
144   my @output = @_;
145   my $ps_num = my $return = my $message = '';
146   my $header_seen = my $num_ps = 0;
147
148   for my $line (@output) {
149     chomp $line;
150     unless ($header_seen) {
151       next until ($line eq "$prompt SHOW POWERSUPPLY");
152       $header_seen++;
153       next;
154     }
155
156     if ($line =~ /^Power supply #(\d+)/) {
157       if ($num_ps) {
158         $return .= $message if ($message);
159         $message = '';
160       }
161       $ps_num = $1;
162       $num_ps++;
163     } elsif ($line =~ /\s+Present\s*:\s+(.*)/) {
164       my $present = $1;
165       if ($present ne 'Yes') {
166         $message = sprintf("PS%d missing ", $ps_num);
167         $exit_status |= 1;
168       }
169     } elsif ($line =~ /\s+Condition\s*:\s+(.*)/) {
170       my $status = $1;
171       if ($status ne 'Ok') {
172         $message = sprintf("PS%d: %s  ", $ps_num, $status);
173         $exit_status |= 2;
174       }
175     } elsif ($line =~ /\s+Redundant\s*:\s+(.*)/) {
176       my $redundant = $1;
177       if ($redundant ne 'Yes') {
178         $message = sprintf("PS%d not redundant ", $ps_num);
179         $exit_status |= 1;
180       }
181     } elsif ($line =~ /($prompt|^\s*$)/) {
182       last;
183     }
184   }
185   $return .= $message if ($message);
186
187   if ($return eq '') {
188     return "POWER OK ($num_ps) ";
189   } else {
190     return $return;
191   }
192 }
193
194 sub do_temp {
195   my @output = @_;
196   my $temp_num = my $return = my $message = '';
197   my $header_seen = my $num_temp = 0;
198
199   for my $line (@output) {
200     chomp $line;
201     unless ($header_seen) {
202       next until ($line eq "$prompt SHOW TEMP");
203       $header_seen++;
204       next;
205     }
206
207     if ($line =~ /^#(\d+)/) {
208       if ($num_temp) {
209         $return .= $message if ($message);
210         $message = '';
211       }
212
213       $temp_num = $1;
214       my @line = split /\s+/, $line;
215
216       my $zone = $line[1];
217       my $current_temp = $line[2];
218       my $threshold = $line[3];
219
220       $current_temp =~ s/(.*)C.*/$1/;
221       $threshold =~ s/(.*)C.*/$1/;
222       next if ($threshold eq '-');
223       $num_temp++;
224
225       my $off = $threshold - $current_temp;
226       if ($off <= 0) {
227         $message = sprintf("TEMP zone=%s %sC/%sC ", $zone, $current_temp, $threshold);
228         $exit_status |= 2;
229       } elsif ($off < ($threshold/10)) {
230         $message = sprintf("TEMP zone=%s %sC/%sC ", $zone, $current_temp, $threshold);
231         $exit_status |= 1;
232       }
233     } elsif ($line =~ /($prompt|^\s*$)/) {
234       last;
235     }
236   }
237   $return .= $message if ($message);
238   if ($return eq '') {
239     return "TEMP OK ($num_temp) ";
240   } else {
241     return $return;
242   }
243 }
244
245 my @output = `echo "$command"|sudo hpasmcli 2>&1`;
246 if (($? >> 8) != 0) {
247   print "UNKNOWN: Can't exec hpasmcli: @output\n";
248   exit 3;
249 }
250
251 for my $line (@output) {
252   chomp $line;
253   for my $check (sort keys %callbacks) {
254     if ($line eq "$prompt $check") {
255       $ret .= &{$callbacks{$check}}(@output);
256     }
257   }
258 }
259
260 if ($exit_status & 2) {
261   print "CRTICAL: $ret\n";
262   exit 2;
263 } elsif ($exit_status & 1) {
264   print "WARNING: $ret\n";
265   exit 1;
266 } else {
267   print "OK: $ret\n";
268   exit 0;
269 }