| 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 | ############ convert the results to the desired unit ############ |
| 310 | my @resultvar=(\$realmem, \$realavail, \$swap, \$swapused, \$totalavail); |
| 311 | foreach my $varref (@resultvar) |
| 312 | { |
| 313 | $$varref/=$unitdiv; |
| 314 | } |
| 315 | |
| 316 | ############ check the thresholds ############ |
| 317 | # do this BEFORE the rounding |
| 318 | my @results = (); |
| 319 | |
| 320 | push (@results, $np->check_threshold( |
| 321 | check => $totalavail, |
| 322 | warning => $np->opts->get("totalavail-warning"), |
| 323 | critical => $np->opts->get("totalavail-critical") |
| 324 | )); |
| 325 | push (@results, $np->check_threshold( |
| 326 | check => $realavail, |
| 327 | warning => $np->opts->get("realavail-warning"), |
| 328 | critical => $np->opts->get("realavail-critical") |
| 329 | )); |
| 330 | |
| 331 | ############ rounding ############ |
| 332 | # show decimals only if value less than limit |
| 333 | foreach my $varref (@resultvar) |
| 334 | { |
| 335 | if ($$varref < 20) |
| 336 | { |
| 337 | $$varref=sprintf("%.2f",$$varref) |
| 338 | } |
| 339 | else |
| 340 | { |
| 341 | $$varref=sprintf("%.0f",$$varref) |
| 342 | } |
| 343 | } |
| 344 | |
| 345 | ############ output the performance data ############ |
| 346 | $np->add_perfdata( |
| 347 | label => "total_avail", |
| 348 | value => $totalavail, |
| 349 | uom => $unitstr, |
| 350 | warning => $np->opts->get("totalavail-warning"), |
| 351 | critical => $np->opts->get("totalavail-critical"), |
| 352 | min => 0, |
| 353 | max => $swap+$realmem |
| 354 | ); |
| 355 | $np->add_perfdata( |
| 356 | label => "real_avail", |
| 357 | value => $realavail, |
| 358 | uom => $unitstr, |
| 359 | warning => $np->opts->get("realavail-warning"), |
| 360 | critical => $np->opts->get("realavail-critical"), |
| 361 | min => 0, |
| 362 | max => $realmem |
| 363 | ); |
| 364 | $np->add_perfdata( |
| 365 | label => "swap_used", |
| 366 | value => $swapused, |
| 367 | uom => $unitstr, |
| 368 | min => 0, |
| 369 | max => $swap |
| 370 | ); |
| 371 | |
| 372 | ############ compose message ############ |
| 373 | $np->nagios_exit( |
| 374 | $np->max_state(@results), |
| 375 | "Real av: $realavail $unitstr, Total av: $totalavail $unitstr, Swapped: $swapused $unitstr", |
| 376 | ); |