Code

Fix for regex input of '|', being output causing problems with Nagios' parsing of
[nagiosplug.git] / contrib / check_apc_ups.pl
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. 
12 use strict;
13 use Getopt::Long;
14 use vars qw($opt_V $opt_h $opt_H $opt_T $opt_t $opt_R $opt_r 
15   $opt_L $opt_l $PROGNAME);
16 use lib "/usr/local/nagios/libexec";
17 use utils qw(%ERRORS &print_revision &support &usage);
19 sub print_help ();
20 sub print_usage ();
21 sub get_snmp_int_val ($);
22 sub escalate_exitval ($);
24 $ENV{'PATH'}='';
25 $ENV{'BASH_ENV'}=''; 
26 $ENV{'ENV'}='';
28 Getopt::Long::Configure('bundling');
29 GetOptions
30         ("V"   => \$opt_V, "version"            => \$opt_V,
31          "h"   => \$opt_h, "help"               => \$opt_h,
32          "T=s" => \$opt_T, "temp-critical"      => \$opt_T,
33          "t=s" => \$opt_t, "temp-warning"       => \$opt_t,
34          "R=s" => \$opt_R, "runtime-critical"   => \$opt_R,
35          "r=s" => \$opt_r, "runtime-warning"    => \$opt_r,
36          "L=s" => \$opt_L, "load-critical"      => \$opt_L,
37          "l=s" => \$opt_l, "load-warning"       => \$opt_l,
38          "H=s" => \$opt_H, "hostname=s"         => \$opt_H);
40 if ($opt_V) {
41         print_revision($PROGNAME,'$Revision: 1771 $');
42         exit $ERRORS{'OK'};
43 }
45 if ($opt_h) {print_help(); exit $ERRORS{'OK'};}
47 ($opt_H) || ($opt_H = shift) || usage("Host name/address not specified\n");
48 my $host = $1 if ($opt_H =~ /([-.A-Za-z0-9]+)/);
49 ($host) || usage("Invalid host: $opt_H\n");
51 # Defaults
53 $opt_R *= 60 * 100 if (defined $opt_R); # Convert minutes to secs/100
54 $opt_r *= 60 * 100 if (defined $opt_R);
56 my $tempcrit    = $opt_T || 60;
57 my $tempwarn    = $opt_t || 40;
58 my $runtimecrit = $opt_R || 30 * 60 * 100;     # Secs / 100
59 my $runtimewarn = $opt_r || 60 * 60 * 100;
60 my $loadcrit    = $opt_L || 85;
61 my $loadwarn    = $opt_l || 50;
63 if ($tempcrit !~ /\d+/) { usage ("Invalid critical temperature threshold.\n"); }
64 if ($tempwarn !~ /\d+/) { usage ("Invalid critical temperature threshold.\n"); }
66 if ($runtimecrit !~ /\d+/) {
67   usage ("Invalid critical run time threshold.\n");
68 }
69 if ($runtimewarn !~ /\d+/) {
70   usage ("Invalid warning run time threshold.\n");
71 }
73 if ($loadcrit !~ /\d+/ || $loadcrit < 0 || $loadcrit > 100) {
74   usage ("Invalid critical load threshold.\n");
75 }
76 if ($loadwarn !~ /\d+/ || $loadwarn < 0 || $loadwarn > 100) {
77   usage ("Invalid warning load threshold.\n");
78 }
81 # APC UPS OIDs
82 # APC MIBs are available at ftp://ftp.apcftp.com/software/pnetmib/mib
83 my $upsBasicOutputStatus          = ".1.3.6.1.4.1.318.1.1.1.4.1.1.0";
84 my $upsBasicBatteryStatus         = ".1.3.6.1.4.1.318.1.1.1.2.1.1.0";
85 my $upsAdvInputLineFailCause      = ".1.3.6.1.4.1.318.1.1.1.3.2.5.0";
86 my $upsAdvBatteryTemperature      = ".1.3.6.1.4.1.318.1.1.1.2.2.2.0";
87 my $upsAdvBatteryRunTimeRemaining = ".1.3.6.1.4.1.318.1.1.1.2.2.3.0";
88 my $upsAdvBatteryReplaceIndicator = ".1.3.6.1.4.1.318.1.1.1.2.2.4.0";
89 my $upsAdvOutputLoad              = ".1.3.6.1.4.1.318.1.1.1.4.2.3.0";
90 my $upsAdvTestDiagnosticsResults  = ".1.3.6.1.4.1.318.1.1.1.7.2.3.0";
92 my @outputStatVals = (
93   [ undef, undef ],                                     # pad 0
94   [ undef, undef ],                                     # pad 1
95   [ "onLine",                   $ERRORS{'OK'} ],        # 2
96   [ "onBattery",                $ERRORS{'WARNING'} ],   # 3
97   [ "onSmartBoost",             $ERRORS{'WARNING'} ],   # 4
98   [ "timedSleeping",            $ERRORS{'WARNING'} ],   # 5
99   [ "softwareBypass",           $ERRORS{'WARNING'} ],   # 6
100   [ "off",                      $ERRORS{'CRITICAL'} ],  # 7
101   [ "rebooting",                $ERRORS{'WARNING'} ],   # 8
102   [ "switchedBypass",           $ERRORS{'WARNING'} ],   # 9
103   [ "hardwareFailureBypass",    $ERRORS{'CRITICAL'} ],  # 10
104   [ "sleepingUntilPowerReturn", $ERRORS{'CRITICAL'} ],  # 11
105   [ "onSmartTrim",              $ERRORS{'WARNING'} ],   # 12
106 );
108 my @failCauseVals = (
109   undef,
110   "noTransfer",
111   "highLineVoltage",
112   "brownout",
113   "blackout",
114   "smallMomentarySag",
115   "deepMomentarySag",
116   "smallMomentarySpike",
117   "largeMomentarySpike",
118   "selfTest",
119   "rateOfVoltageChnage",
120 );
122 my @battStatVals = (
123   [ undef, undef ],                             # pad 0
124   [ undef, undef ],                             # pad 1
125   [ "batteryNormal",    $ERRORS{'OK'} ],        # 2
126   [ "batteryLow",       $ERRORS{'CRITICAL'} ],  # 3
127 );
129 my @battReplVals = (
130   [ undef, undef ],                                     # pad 0
131   [ "noBatteryNeedsReplacing",  $ERRORS{'OK'} ],        # 1
132   [ "batteryNeedsReplacing",    $ERRORS{'CRITICAL'} ],  # 2
133 );
135 my @diagnosticsResultsVals = (
136   [ undef, undef ],                             # pad 0
137   [ "OK",               $ERRORS{'OK'} ],        # 1
138   [ "failed",           $ERRORS{'CRITICAL'} ],  # 2
139   [ "invalidTest",      $ERRORS{'CRITICAL'} ],  # 3
140   [ "testInProgress",   $ERRORS{'OK'} ],        # 4
141 );
143 my $exitval     = $ERRORS{'UNKNOWN'};
144 my $data;
145 my $onbattery   = 3;
147 $data = get_snmp_int_val( $upsBasicOutputStatus );
149 print "Output status: ";
150 if (defined ($data) && defined ($outputStatVals[$data][0])) {
151   print "$outputStatVals[$data][0] | ";
152   escalate_exitval($outputStatVals[$data][1]);
153 } else {
154   print "unknown | ";
157 $data = get_snmp_int_val( $upsAdvBatteryRunTimeRemaining );
159 print "Rem time: ";
160 if (defined ($data)) {
161   my $hrs  = int($data / (60 * 60 * 100)); # Data is hundredths of a second
162   my $mins = int($data / (60 * 100)) % 60;
163   my $secs = ($data % 100) / 100;
164   printf "%d:%02d:%05.2f | ", $hrs, $mins, $secs;
165   if ($data <= $runtimecrit) {
166     escalate_exitval($ERRORS{'CRITICAL'});
167   } elsif ($data <= $runtimewarn) {
168     escalate_exitval($ERRORS{'WARNING'});
169   } else {
170     escalate_exitval($ERRORS{'OK'});
171   }
172 } else {
173   print "unknown | ";
176 $data = get_snmp_int_val( $upsBasicBatteryStatus );
178 print "Battery status: ";
179 if (defined ($data) && defined ($battStatVals[$data][0])) {
180   my $failcause = "unknown";
181   my $fc = get_snmp_int_val( $upsAdvInputLineFailCause );
182   if ($data == $onbattery) {
183     if (defined ($failCauseVals[$fc])) { $failcause = $failCauseVals[$fc]; }
184     print "$battStatVals[$data][0] ($failcause) | ";
185   } else {
186     print "$battStatVals[$data][0] | ";
187   }
188   escalate_exitval($battStatVals[$data][1]);
189 } else {
190   print "unknown | ";
193 $data = get_snmp_int_val( $upsAdvBatteryTemperature );
195 print "Battery temp(C): ";
196 if (defined ($data)) {
197   print "$data | ";
198   if ($data >= $tempcrit) {
199     escalate_exitval($ERRORS{'CRITICAL'});
200   } elsif ($data >= $tempwarn) {
201     escalate_exitval($ERRORS{'WARNING'});
202   } else {
203     escalate_exitval($ERRORS{'OK'});
204   }
205 } else {
206   print "unknown | ";
209 $data = get_snmp_int_val( $upsAdvBatteryReplaceIndicator );
211 print "Battery repl: ";
212 if (defined ($data) && defined ($battReplVals[$data][0])) {
213   print "$battReplVals[$data][0] | ";
214   escalate_exitval($battReplVals[$data][1]);
215 } else {
216   print "unknown | ";
219 $data = get_snmp_int_val( $upsAdvOutputLoad );
221 print "Output load (%): ";
222 if (defined ($data)) {
223   print "$data | ";
224   if ($data >= $loadcrit) {
225     escalate_exitval($ERRORS{'CRITICAL'});
226   } elsif ($data >= $loadwarn) {
227     escalate_exitval($ERRORS{'WARNING'});
228   } else {
229     escalate_exitval($ERRORS{'OK'});
230   }
231 } else {
232   print "unknown | ";
235 $data = get_snmp_int_val( $upsAdvTestDiagnosticsResults );
237 print "Diag result: ";
238 if (defined ($data) && defined ($diagnosticsResultsVals[$data][0])) {
239   print "$diagnosticsResultsVals[$data][0]\n";
240   escalate_exitval($diagnosticsResultsVals[$data][1]);
241 } else {
242   print "unknown\n";
246 exit $exitval;
249 sub print_usage () {
250         print "Usage: $PROGNAME -H <host> -T temp -t temp -R minutes -r minutes\n";
251         print "  -L percent -l percent\n";
254 sub print_help () {
255         print_revision($PROGNAME,'$Revision: 1771 $');
256         print "Copyright (c) 2001 Gerald Combs/Jeffrey Blank/Karl DeBisschop
258 This plugin reports the status of an APC UPS equipped with an SNMP management
259 module.
261 ";
262         print_usage();
263         print "
264 -H, --hostname=HOST
265    Name or IP address of host to check
266 -T --temp-critical
267    Battery degrees C above which a CRITICAL status will result (default: 60)
268 -t --temp-warning
269    Battery degrees C above which a WARNING status will result (default: 40)
270 -R --runtime-critical
271    Minutes remaining below which a CRITICAL status will result (default: 30)
272 -r --runtime-warning
273    Minutes remaining below which a WARNING status will result (default: 60)
274 -L --load-critical
275    Output load pct above which a CRITICAL status will result (default: 85
276 -l --load-warning
277    Output load pct above which a WARNING status will result (default: 50
279 ";
280         support();
283 sub get_snmp_int_val ($) {
284   my $val=0;
285   my $oid = shift(@_);
287   $val = `/usr/bin/snmpget $host public $oid 2> /dev/null`;
288   my @test = split(/ /,$val,3);
290   return undef unless (defined ($test[2]));
292   if ($test[2] =~ /\(\d+\)/) {  # Later versions of UCD SNMP
293     ($val) = ($test[2] =~ /\((\d+)\)/);
294   } elsif ($test[2] =~ /: \d+/) {
295     ($val) = ($test[2] =~ /: (\d+)/);
296   } else {
297     $val = $test[2];
298   }
300   return $val;
303 sub escalate_exitval ($) {
304   my $newval = shift(@_);
306   if ($newval > $exitval) { $exitval = $newval; }