add percent output
[nagios-monitoring] / check_mem_ucd_snmp / check_mem_ucd_snmp
1 #!/usr/bin/perl -w
2 #
3 # check_mem_ucd_snmp: nagios-check testing the memory of a linux-system via SNMP
4 #
5 # see http://www.intra2net.com/en/developer/monitoring/
6 # for current version, documentation, contact information etc.
7 #
8 # (C) 2009 by Gerd v. Egidy <gerd.von.egidy@intra2net.com>
9 #
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 # GNU General Public License for more details.
19 #
20
21 use strict;
22 use Nagios::Plugin;
23 use Net::SNMP;
24 use Data::Dumper;
25
26 ############ basic plugin data & argument handling ############
27 my $np = Nagios::Plugin->new(
28             plugin  => "check_mem_ucd_snmp",
29             version => "0.1",
30             blurb   => "nagios-check testing the memory of a linux-system via SNMP",
31             usage   => "Usage: %s [-h|--help] -H <hostname> [-p <port>] [-t <timeout>] [-T <retries>] [-v] [-i (KB|MB|GB)]\n"
32                      . "[-1 | -2] [-c <community>]\n"
33                      . "[-3] [-u <username>] [-a (md5|sha)] [-A <authpasswd>] [-x (des|aes)] [-X <privpasswd>]\n"
34                      . "     [-E <contextengineid>] [-n <contextname>]\n"
35                      . "[-m <total-threshold>] [-M <total-threshold>] [-r <real-threshold>] [-R <real-threshold>]",
36             extra   => "\nAll thresholds are in nagios standard format, see\n"
37                      . "http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT\n"
38                      . "for a description\n"
39                      . "\n"
40                      . "This check does currently not support setting the security engine id.\n",
41             url     => "http://www.intra2net.com/en/developer/monitoring/",
42             license => "This nagios plugin is free software, and comes with ABSOLUTELY\n"
43                      . "NO WARRANTY. It may be used, redistributed and/or modified under\n"
44                      . "the terms of the GNU General Public Licence; either version 2\n"
45                      . "of the License, or (at your option) any later version."
46         );
47
48 # basic options
49 $np->add_arg(
50         spec     => "hostname|H=s",
51         help     => "hostname or IP",
52         required => 1
53     );
54 $np->add_arg(
55         spec     => "port|p=i",
56         help     => "portnumber",
57         default  => 161
58     );
59 $np->add_arg(
60         spec     => "retries|T=i",
61         help     => "SNMP retries on error, default: %s",
62         default  => 1
63     );
64 $np->add_arg(
65         spec     => "unit|i=s",
66         help     => "unit for output and thresholds (KB|MB|GB), default: %s",
67         default  => "MB"
68     );
69
70 # snmp v1/v2c
71 $np->add_arg(
72         spec     => "snmpv1|1",
73         help     => "use SNMP version 1"
74     );
75 $np->add_arg(
76         spec     => "snmpv2c|2",
77         help     => "use SNMP version 2c"
78     );
79 $np->add_arg(
80         spec     => "community|c=s",
81         help     => "SNMPv1/SNMPv2c community name, default: %s",
82         default  => "public"
83     );
84
85 # snmp v3
86 $np->add_arg(
87         spec     => "snmpv3|3",
88         help     => "use SNMP version 3"
89     );
90
91 $np->add_arg(
92         spec     => "username|u=s",
93         help     => "SNMPv3 username"
94     );
95 $np->add_arg(
96         spec     => "authprotocol|a=s",
97         help     => "SNMPv3 authentication protocol (md5|sha), default: %s",
98         default  => "md5"
99     );
100 $np->add_arg(
101         spec     => "authpassword|A=s",
102         help     => "SNMPv3 authentication password"
103     );
104 $np->add_arg(
105         spec     => "privprotocol|x=s",
106         help     => "SNMPv3 privacy protocol (des|aes), default: %s",
107         default  => "des"
108     );
109 $np->add_arg(
110         spec     => "privpassword|X=s",
111         help     => "SNMPv3 privacy password"
112     );
113 $np->add_arg(
114         spec     => "contextengineid|E=s",
115         help     => "SNMPv3 context engine ID"
116     );
117 $np->add_arg(
118         spec     => "contextname|n=s",
119         help     => "SNMPv3 context name"
120     );
121
122 # thresholds
123 $np->add_arg(
124         spec     => "totalavail-warning|m=s",
125         help     => "Warning threshold for the total memory (real+swap) available, default: %s",
126         label    => [ "FLOAT:FLOAT" ],
127         default  => "500:"
128     );
129 $np->add_arg(
130         spec     => "totalavail-critical|M=s",
131         help     => "Critical threshold for the total memory (real+swap) available, default: %s",
132         label    => [ "FLOAT:FLOAT" ],
133         default  => "200:"
134     );
135 $np->add_arg(
136         spec     => "realavail-warning|r=s",
137         help     => "Warning threshold for the real memory available (free+buffer+cache), default: %s",
138         label    => [ "FLOAT:FLOAT" ],
139         default  => "200:"
140     );
141 $np->add_arg(
142         spec     => "realavail-critical|R=s",
143         help     => "Critical threshold for the real memory available (free+buffer+cache), default: %s",
144         label    => [ "FLOAT:FLOAT" ],
145         default  => "50:"
146     );
147
148 # parse arguments
149 $np->getopts;
150
151 ############ check & handle the unit parameter ############
152 my $unitstr;
153 my $unitdiv;
154 if (uc($np->opts->get("unit")) eq "KB")
155 {
156     $unitstr="KB";
157     $unitdiv=1;
158 }
159 elsif (uc($np->opts->get("unit")) eq "MB")
160 {
161     $unitstr="MB";
162     $unitdiv=1024;
163 }
164 elsif (uc($np->opts->get("unit")) eq "GB")
165 {
166     $unitstr="GB";
167     $unitdiv=1024*1024;
168 }
169 else
170 {
171     $np->nagios_die("illegal unit requested");
172 }
173
174 ############ sanity-check the snmp-version ############
175 my $snmpversion=undef;
176
177 if ($np->opts->get("snmpv1"))
178 {
179     $snmpversion=1;
180 }
181 if ($np->opts->get("snmpv2c"))
182 {
183     if (defined $snmpversion)
184     {
185         $np->nagios_die("you can only define one SNMP version");
186     }
187     else
188     {
189         $snmpversion=2;
190     }
191 }
192 if ($np->opts->get("snmpv3"))
193 {
194     if (defined $snmpversion)
195     {
196         $np->nagios_die("you can only define one SNMP version");
197     }
198     else
199     {
200         $snmpversion=3;
201     }
202 }
203 if (not defined $snmpversion)
204 {
205     # snmp default version
206     $snmpversion=2;
207 }
208
209 ############ create the SNMP session ############
210 my %snmpsessionparam = (
211                         -hostname   => $np->opts->get("hostname"),
212                         -port       => $np->opts->get("port"),
213                         -version    => $snmpversion,
214                         -timeout    => $np->opts->get("timeout"),
215                         -retries    => $np->opts->get("retries"),
216                         );
217 my %snmprequestparam = ();
218
219 if ($snmpversion == 1 || $snmpversion == 2)
220 {
221     $snmpsessionparam{-community}=$np->opts->get("community");
222 }
223 else
224 {
225     $snmpsessionparam{-username}=$np->opts->get("username");
226
227     if (defined $np->opts->get("authpassword"))
228     {
229         $snmpsessionparam{-authprotocol}=$np->opts->get("authprotocol");
230         $snmpsessionparam{-authpassword}=$np->opts->get("authpassword");
231     }
232
233     if (defined $np->opts->get("privpassword"))
234     {
235         $snmpsessionparam{-privprotocol}=$np->opts->get("privprotocol");
236         $snmpsessionparam{-privpassword}=$np->opts->get("privpassword");
237     }
238
239     if (defined $np->opts->get("contextname"))
240     {
241         $snmprequestparam{-contextname}=$np->opts->get("contextname");
242     }
243     if (defined $np->opts->get("contextengineid"))
244     {
245         $snmprequestparam{-contextengineid}=$np->opts->get("contextengineid");
246     }
247 }
248
249 ($np->opts->get("verbose") > 1) && print Data::Dumper->Dump([\%snmpsessionparam], [qw(snmp_session_data)]);
250
251 my ($session,$snmperror)=Net::SNMP->session(%snmpsessionparam);
252
253 if (!defined $session)
254 {
255     $np->nagios_die("Error opening SNMP session: $snmperror");
256 }
257
258 ############ prepare & execute the snmp request ############
259 my $oid_memTotalSwap  = "1.3.6.1.4.1.2021.4.3.0";
260 my $oid_memAvailSwap  = "1.3.6.1.4.1.2021.4.4.0";
261 my $oid_memTotalReal  = "1.3.6.1.4.1.2021.4.5.0";
262 my $oid_memAvailReal  = "1.3.6.1.4.1.2021.4.6.0";
263 my $oid_memBuffer     = "1.3.6.1.4.1.2021.4.14.0";
264 my $oid_memCached     = "1.3.6.1.4.1.2021.4.15.0";
265 my $oid_ssSwapIn      = "1.3.6.1.4.1.2021.11.3.0";
266 my $oid_ssSwapOut     = "1.3.6.1.4.1.2021.11.4.0";
267 my $oid_intranator_swap_warning = "1.3.6.1.4.1.30475.1.1.3";
268
269 # we really need these oids to complete the check
270 my @essential_oidlist = ($oid_memTotalSwap, $oid_memAvailSwap, $oid_memTotalReal, $oid_memAvailReal,
271                          $oid_memBuffer, $oid_memCached);
272 # all oids, including the additional ones
273 my @oidlist = (@essential_oidlist, $oid_ssSwapIn, $oid_ssSwapOut, $oid_intranator_swap_warning);
274
275 my %thisrequest=%snmprequestparam;
276 $thisrequest{-varbindlist}=\@oidlist;
277
278 ($np->opts->get("verbose") > 2) && print Data::Dumper->Dump([\%thisrequest], [qw(snmp_request_data)]);
279
280 my $result = $session->get_request(%thisrequest);
281 if (!defined $result)
282 {
283     $snmperror=$session->error;
284     $session->close();
285     $np->nagios_die("Error in SNMP request: $snmperror");
286 }
287
288 ($np->opts->get("verbose") > 0) && print Data::Dumper->Dump([$result], [qw(snmp_result)]);
289
290 $session->close();
291
292 ############ check if the essential oids are there ############
293 foreach my $oid (@essential_oidlist)
294 {
295     if (!defined $result->{$oid} || $result->{$oid} eq "noSuchObject")
296     {
297         $np->nagios_die("Essential OID $oid missing in result");
298     }
299 }
300
301 ############ interpret the results ############
302 # use only OIDs listed as essential here!
303 my $realmem=$result->{$oid_memTotalReal};
304 my $realavail=$result->{$oid_memAvailReal}+$result->{$oid_memBuffer}+$result->{$oid_memCached};
305 my $swap=$result->{$oid_memTotalSwap};
306 my $swapused=$swap-$result->{$oid_memAvailSwap};
307 my $totalavail=$realavail+$result->{$oid_memAvailSwap};
308
309 my $realpercent=sprintf("%.0f",($realavail/$realmem)*100);
310 my $totalpercent=sprintf("%.0f",($totalavail/($realmem+$swap))*100);
311 my $swappercent=sprintf("%.0f",($swapused/$swap)*100);
312
313 ############ convert the results to the desired unit ############
314 my @resultvar=(\$realmem, \$realavail, \$swap, \$swapused, \$totalavail);
315 foreach my $varref (@resultvar) 
316 {
317     $$varref/=$unitdiv;
318 }
319
320 ############ check the thresholds ############
321 # do this BEFORE the rounding
322 my @results = ();
323
324 push (@results, $np->check_threshold(
325         check    => $totalavail,
326         warning  => $np->opts->get("totalavail-warning"),
327         critical => $np->opts->get("totalavail-critical")
328     ));
329 push (@results, $np->check_threshold(
330         check    => $realavail,
331         warning  => $np->opts->get("realavail-warning"),
332         critical => $np->opts->get("realavail-critical")
333     ));
334
335 ############ rounding ############
336 # show decimals only if value less than limit
337 foreach my $varref (@resultvar)
338 {
339     if ($$varref < 20)
340     {
341         $$varref=sprintf("%.2f",$$varref)
342     }
343     else
344     {
345         $$varref=sprintf("%.0f",$$varref)
346     }
347 }
348
349 ############ output the performance data ############
350 $np->add_perfdata(
351         label     => "total_avail",
352         value     => $totalavail,
353         uom       => $unitstr,
354         warning   => $np->opts->get("totalavail-warning"),
355         critical  => $np->opts->get("totalavail-critical"),
356         min       => 0,
357         max       => $swap+$realmem
358      );
359 $np->add_perfdata(
360         label     => "real_avail",
361         value     => $realavail,
362         uom       => $unitstr,
363         warning   => $np->opts->get("realavail-warning"),
364         critical  => $np->opts->get("realavail-critical"),
365         min       => 0,
366         max       => $realmem
367      );
368 $np->add_perfdata(
369         label     => "swap_used",
370         value     => $swapused,
371         uom       => $unitstr,
372         min       => 0,
373         max       => $swap
374      );
375
376 ############ compose message ############
377 $np->nagios_exit(
378         $np->max_state(@results),
379         "Real av: $realavail $unitstr ($realpercent%), Total av: $totalavail $unitstr ($totalpercent%), Swapped: $swapused $unitstr ($swappercent%)",
380      );