diff options
Diffstat (limited to 'contrib/check_apc_ups.pl')
-rw-r--r-- | contrib/check_apc_ups.pl | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/contrib/check_apc_ups.pl b/contrib/check_apc_ups.pl new file mode 100644 index 0000000..dd979f5 --- /dev/null +++ b/contrib/check_apc_ups.pl | |||
@@ -0,0 +1,314 @@ | |||
1 | #! /usr/bin/perl -wT | ||
2 | # | ||
3 | # Check_apc_ups - Check APC UPS status via SNMP | ||
4 | # Shamelessly copied from check_breeze.pl | ||
5 | # | ||
6 | # To do: | ||
7 | # - Send SNMP queries directly, instead of forking `snmpget`. | ||
8 | # - Make the status less verbose. Maybe we can send an "onLine, time | ||
9 | # remaining: hh:mm:ss" if all is well, and a list of specific problems | ||
10 | # if something is broken. | ||
11 | |||
12 | BEGIN { | ||
13 | if ($0 =~ m/^(.*?)[\/\\]([^\/\\]+)$/) { | ||
14 | $runtimedir = $1; | ||
15 | $PROGNAME = $2; | ||
16 | } | ||
17 | } | ||
18 | |||
19 | use strict; | ||
20 | use Getopt::Long; | ||
21 | use vars qw($opt_V $opt_h $opt_H $opt_T $opt_t $opt_R $opt_r | ||
22 | $opt_L $opt_l $PROGNAME); | ||
23 | use lib $main::runtimedir; | ||
24 | use utils qw(%ERRORS &print_revision &support &usage); | ||
25 | |||
26 | sub print_help (); | ||
27 | sub print_usage (); | ||
28 | sub get_snmp_int_val ($); | ||
29 | sub escalate_exitval ($); | ||
30 | |||
31 | $ENV{'PATH'}=''; | ||
32 | $ENV{'BASH_ENV'}=''; | ||
33 | $ENV{'ENV'}=''; | ||
34 | |||
35 | Getopt::Long::Configure('bundling'); | ||
36 | GetOptions | ||
37 | ("V" => \$opt_V, "version" => \$opt_V, | ||
38 | "h" => \$opt_h, "help" => \$opt_h, | ||
39 | "T=s" => \$opt_T, "temp-critical" => \$opt_T, | ||
40 | "t=s" => \$opt_t, "temp-warning" => \$opt_t, | ||
41 | "R=s" => \$opt_R, "runtime-critical" => \$opt_R, | ||
42 | "r=s" => \$opt_r, "runtime-warning" => \$opt_r, | ||
43 | "L=s" => \$opt_L, "load-critical" => \$opt_L, | ||
44 | "l=s" => \$opt_l, "load-warning" => \$opt_l, | ||
45 | "H=s" => \$opt_H, "hostname=s" => \$opt_H); | ||
46 | |||
47 | if ($opt_V) { | ||
48 | print_revision($PROGNAME,'$Revision$'); | ||
49 | exit $ERRORS{'OK'}; | ||
50 | } | ||
51 | |||
52 | if ($opt_h) {print_help(); exit $ERRORS{'OK'};} | ||
53 | |||
54 | ($opt_H) || ($opt_H = shift) || usage("Host name/address not specified\n"); | ||
55 | my $host = $1 if ($opt_H =~ /([-.A-Za-z0-9]+)/); | ||
56 | ($host) || usage("Invalid host: $opt_H\n"); | ||
57 | |||
58 | # Defaults | ||
59 | |||
60 | $opt_R *= 60 * 100 if (defined $opt_R); # Convert minutes to secs/100 | ||
61 | $opt_r *= 60 * 100 if (defined $opt_R); | ||
62 | |||
63 | my $tempcrit = $opt_T || 60; | ||
64 | my $tempwarn = $opt_t || 40; | ||
65 | my $runtimecrit = $opt_R || 30 * 60 * 100; # Secs / 100 | ||
66 | my $runtimewarn = $opt_r || 60 * 60 * 100; | ||
67 | my $loadcrit = $opt_L || 85; | ||
68 | my $loadwarn = $opt_l || 50; | ||
69 | |||
70 | if ($tempcrit !~ /\d+/) { usage ("Invalid critical temperature threshold.\n"); } | ||
71 | if ($tempwarn !~ /\d+/) { usage ("Invalid critical temperature threshold.\n"); } | ||
72 | |||
73 | if ($runtimecrit !~ /\d+/) { | ||
74 | usage ("Invalid critical run time threshold.\n"); | ||
75 | } | ||
76 | if ($runtimewarn !~ /\d+/) { | ||
77 | usage ("Invalid warning run time threshold.\n"); | ||
78 | } | ||
79 | |||
80 | if ($loadcrit !~ /\d+/ || $loadcrit < 0 || $loadcrit > 100) { | ||
81 | usage ("Invalid critical load threshold.\n"); | ||
82 | } | ||
83 | if ($loadwarn !~ /\d+/ || $loadwarn < 0 || $loadwarn > 100) { | ||
84 | usage ("Invalid warning load threshold.\n"); | ||
85 | } | ||
86 | |||
87 | |||
88 | # APC UPS OIDs | ||
89 | # APC MIBs are available at ftp://ftp.apcftp.com/software/pnetmib/mib | ||
90 | my $upsBasicOutputStatus = ".1.3.6.1.4.1.318.1.1.1.4.1.1.0"; | ||
91 | my $upsBasicBatteryStatus = ".1.3.6.1.4.1.318.1.1.1.2.1.1.0"; | ||
92 | my $upsAdvInputLineFailCause = ".1.3.6.1.4.1.318.1.1.1.3.2.5.0"; | ||
93 | my $upsAdvBatteryTemperature = ".1.3.6.1.4.1.318.1.1.1.2.2.2.0"; | ||
94 | my $upsAdvBatteryRunTimeRemaining = ".1.3.6.1.4.1.318.1.1.1.2.2.3.0"; | ||
95 | my $upsAdvBatteryReplaceIndicator = ".1.3.6.1.4.1.318.1.1.1.2.2.4.0"; | ||
96 | my $upsAdvOutputLoad = ".1.3.6.1.4.1.318.1.1.1.4.2.3.0"; | ||
97 | my $upsAdvTestDiagnosticsResults = ".1.3.6.1.4.1.318.1.1.1.7.2.3.0"; | ||
98 | |||
99 | my @outputStatVals = ( | ||
100 | [ undef, undef ], # pad 0 | ||
101 | [ undef, undef ], # pad 1 | ||
102 | [ "onLine", $ERRORS{'OK'} ], # 2 | ||
103 | [ "onBattery", $ERRORS{'WARNING'} ], # 3 | ||
104 | [ "onSmartBoost", $ERRORS{'WARNING'} ], # 4 | ||
105 | [ "timedSleeping", $ERRORS{'WARNING'} ], # 5 | ||
106 | [ "softwareBypass", $ERRORS{'WARNING'} ], # 6 | ||
107 | [ "off", $ERRORS{'CRITICAL'} ], # 7 | ||
108 | [ "rebooting", $ERRORS{'WARNING'} ], # 8 | ||
109 | [ "switchedBypass", $ERRORS{'WARNING'} ], # 9 | ||
110 | [ "hardwareFailureBypass", $ERRORS{'CRITICAL'} ], # 10 | ||
111 | [ "sleepingUntilPowerReturn", $ERRORS{'CRITICAL'} ], # 11 | ||
112 | [ "onSmartTrim", $ERRORS{'WARNING'} ], # 12 | ||
113 | ); | ||
114 | |||
115 | my @failCauseVals = ( | ||
116 | undef, | ||
117 | "noTransfer", | ||
118 | "highLineVoltage", | ||
119 | "brownout", | ||
120 | "blackout", | ||
121 | "smallMomentarySag", | ||
122 | "deepMomentarySag", | ||
123 | "smallMomentarySpike", | ||
124 | "largeMomentarySpike", | ||
125 | "selfTest", | ||
126 | "rateOfVoltageChnage", | ||
127 | ); | ||
128 | |||
129 | my @battStatVals = ( | ||
130 | [ undef, undef ], # pad 0 | ||
131 | [ undef, undef ], # pad 1 | ||
132 | [ "batteryNormal", $ERRORS{'OK'} ], # 2 | ||
133 | [ "batteryLow", $ERRORS{'CRITICAL'} ], # 3 | ||
134 | ); | ||
135 | |||
136 | my @battReplVals = ( | ||
137 | [ undef, undef ], # pad 0 | ||
138 | [ "noBatteryNeedsReplacing", $ERRORS{'OK'} ], # 1 | ||
139 | [ "batteryNeedsReplacing", $ERRORS{'CRITICAL'} ], # 2 | ||
140 | ); | ||
141 | |||
142 | my @diagnosticsResultsVals = ( | ||
143 | [ undef, undef ], # pad 0 | ||
144 | [ "OK", $ERRORS{'OK'} ], # 1 | ||
145 | [ "failed", $ERRORS{'CRITICAL'} ], # 2 | ||
146 | [ "invalidTest", $ERRORS{'CRITICAL'} ], # 3 | ||
147 | [ "testInProgress", $ERRORS{'OK'} ], # 4 | ||
148 | ); | ||
149 | |||
150 | my $exitval = $ERRORS{'UNKNOWN'}; | ||
151 | my $data; | ||
152 | my $onbattery = 3; | ||
153 | |||
154 | $data = get_snmp_int_val( $upsBasicOutputStatus ); | ||
155 | |||
156 | print "Output status: "; | ||
157 | if (defined ($data) && defined ($outputStatVals[$data][0])) { | ||
158 | print "$outputStatVals[$data][0] | "; | ||
159 | escalate_exitval($outputStatVals[$data][1]); | ||
160 | } else { | ||
161 | print "unknown | "; | ||
162 | } | ||
163 | |||
164 | $data = get_snmp_int_val( $upsAdvBatteryRunTimeRemaining ); | ||
165 | |||
166 | print "Rem time: "; | ||
167 | if (defined ($data)) { | ||
168 | my $hrs = int($data / (60 * 60 * 100)); # Data is hundredths of a second | ||
169 | my $mins = int($data / (60 * 100)) % 60; | ||
170 | my $secs = ($data % 100) / 100; | ||
171 | printf "%d:%02d:%05.2f | ", $hrs, $mins, $secs; | ||
172 | if ($data <= $runtimecrit) { | ||
173 | escalate_exitval($ERRORS{'CRITICAL'}); | ||
174 | } elsif ($data <= $runtimewarn) { | ||
175 | escalate_exitval($ERRORS{'WARNING'}); | ||
176 | } else { | ||
177 | escalate_exitval($ERRORS{'OK'}); | ||
178 | } | ||
179 | } else { | ||
180 | print "unknown | "; | ||
181 | } | ||
182 | |||
183 | $data = get_snmp_int_val( $upsBasicBatteryStatus ); | ||
184 | |||
185 | print "Battery status: "; | ||
186 | if (defined ($data) && defined ($battStatVals[$data][0])) { | ||
187 | my $failcause = "unknown"; | ||
188 | my $fc = get_snmp_int_val( $upsAdvInputLineFailCause ); | ||
189 | if ($data == $onbattery) { | ||
190 | if (defined ($failCauseVals[$fc])) { $failcause = $failCauseVals[$fc]; } | ||
191 | print "$battStatVals[$data][0] ($failcause) | "; | ||
192 | } else { | ||
193 | print "$battStatVals[$data][0] | "; | ||
194 | } | ||
195 | escalate_exitval($battStatVals[$data][1]); | ||
196 | } else { | ||
197 | print "unknown | "; | ||
198 | } | ||
199 | |||
200 | $data = get_snmp_int_val( $upsAdvBatteryTemperature ); | ||
201 | |||
202 | print "Battery temp(C): "; | ||
203 | if (defined ($data)) { | ||
204 | print "$data | "; | ||
205 | if ($data >= $tempcrit) { | ||
206 | escalate_exitval($ERRORS{'CRITICAL'}); | ||
207 | } elsif ($data >= $tempwarn) { | ||
208 | escalate_exitval($ERRORS{'WARNING'}); | ||
209 | } else { | ||
210 | escalate_exitval($ERRORS{'OK'}); | ||
211 | } | ||
212 | } else { | ||
213 | print "unknown | "; | ||
214 | } | ||
215 | |||
216 | $data = get_snmp_int_val( $upsAdvBatteryReplaceIndicator ); | ||
217 | |||
218 | print "Battery repl: "; | ||
219 | if (defined ($data) && defined ($battReplVals[$data][0])) { | ||
220 | print "$battReplVals[$data][0] | "; | ||
221 | escalate_exitval($battReplVals[$data][1]); | ||
222 | } else { | ||
223 | print "unknown | "; | ||
224 | } | ||
225 | |||
226 | $data = get_snmp_int_val( $upsAdvOutputLoad ); | ||
227 | |||
228 | print "Output load (%): "; | ||
229 | if (defined ($data)) { | ||
230 | print "$data | "; | ||
231 | if ($data >= $loadcrit) { | ||
232 | escalate_exitval($ERRORS{'CRITICAL'}); | ||
233 | } elsif ($data >= $loadwarn) { | ||
234 | escalate_exitval($ERRORS{'WARNING'}); | ||
235 | } else { | ||
236 | escalate_exitval($ERRORS{'OK'}); | ||
237 | } | ||
238 | } else { | ||
239 | print "unknown | "; | ||
240 | } | ||
241 | |||
242 | $data = get_snmp_int_val( $upsAdvTestDiagnosticsResults ); | ||
243 | |||
244 | print "Diag result: "; | ||
245 | if (defined ($data) && defined ($diagnosticsResultsVals[$data][0])) { | ||
246 | print "$diagnosticsResultsVals[$data][0]\n"; | ||
247 | escalate_exitval($diagnosticsResultsVals[$data][1]); | ||
248 | } else { | ||
249 | print "unknown\n"; | ||
250 | } | ||
251 | |||
252 | |||
253 | exit $exitval; | ||
254 | |||
255 | |||
256 | sub print_usage () { | ||
257 | print "Usage: $PROGNAME -H <host> -T temp -t temp -R minutes -r minutes\n"; | ||
258 | print " -L percent -l percent\n"; | ||
259 | } | ||
260 | |||
261 | sub print_help () { | ||
262 | print_revision($PROGNAME,'$Revision$'); | ||
263 | print "Copyright (c) 2001 Gerald Combs/Jeffrey Blank/Karl DeBisschop | ||
264 | |||
265 | This plugin reports the status of an APC UPS equipped with an SNMP management | ||
266 | module. | ||
267 | |||
268 | "; | ||
269 | print_usage(); | ||
270 | print " | ||
271 | -H, --hostname=HOST | ||
272 | Name or IP address of host to check | ||
273 | -T --temp-critical | ||
274 | Battery degrees C above which a CRITICAL status will result (default: 60) | ||
275 | -t --temp-warning | ||
276 | Battery degrees C above which a WARNING status will result (default: 40) | ||
277 | -R --runtime-critical | ||
278 | Minutes remaining below which a CRITICAL status will result (default: 30) | ||
279 | -r --runtime-warning | ||
280 | Minutes remaining below which a WARNING status will result (default: 60) | ||
281 | -L --load-critical | ||
282 | Output load pct above which a CRITICAL status will result (default: 85 | ||
283 | -l --load-warning | ||
284 | Output load pct above which a WARNING status will result (default: 50 | ||
285 | |||
286 | "; | ||
287 | support(); | ||
288 | } | ||
289 | |||
290 | sub get_snmp_int_val ($) { | ||
291 | my $val=0; | ||
292 | my $oid = shift(@_); | ||
293 | |||
294 | $val = `/usr/bin/snmpget $host public $oid 2> /dev/null`; | ||
295 | my @test = split(/ /,$val,3); | ||
296 | |||
297 | return undef unless (defined ($test[2])); | ||
298 | |||
299 | if ($test[2] =~ /\(\d+\)/) { # Later versions of UCD SNMP | ||
300 | ($val) = ($test[2] =~ /\((\d+)\)/); | ||
301 | } elsif ($test[2] =~ /: \d+/) { | ||
302 | ($val) = ($test[2] =~ /: (\d+)/); | ||
303 | } else { | ||
304 | $val = $test[2]; | ||
305 | } | ||
306 | |||
307 | return $val; | ||
308 | } | ||
309 | |||
310 | sub escalate_exitval ($) { | ||
311 | my $newval = shift(@_); | ||
312 | |||
313 | if ($newval > $exitval) { $exitval = $newval; } | ||
314 | } | ||