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