#!/usr/bin/perl -w # # check_mem_ucd_snmp: nagios-check testing the memory of a linux-system via SNMP # # see http://www.intra2net.com/en/developer/monitoring/ # for current version, documentation, contact information etc. # # (C) 2009 by Gerd v. Egidy # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # use strict; use Nagios::Plugin; use Net::SNMP; use Data::Dumper; ############ basic plugin data & argument handling ############ my $np = Nagios::Plugin->new( plugin => "check_mem_ucd_snmp", version => "0.1", blurb => "nagios-check testing the memory of a linux-system via SNMP", usage => "Usage: %s [-h|--help] -H [-p ] [-t ] [-T ] [-v] [-i (KB|MB|GB)]\n" . "[-1 | -2] [-c ]\n" . "[-3] [-u ] [-a (md5|sha)] [-A ] [-x (des|aes)] [-X ]\n" . " [-E ] [-n ]\n" . "[-m ] [-M ] [-r ] [-R ]", extra => "\nAll thresholds are in nagios standard format, see\n" . "http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT\n" . "for a description\n" . "\n" . "This check does currently not support setting the security engine id.\n", url => "http://www.intra2net.com/en/developer/monitoring/", license => "This nagios plugin is free software, and comes with ABSOLUTELY\n" . "NO WARRANTY. It may be used, redistributed and/or modified under\n" . "the terms of the GNU General Public Licence; either version 2\n" . "of the License, or (at your option) any later version." ); # basic options $np->add_arg( spec => "hostname|H=s", help => "hostname or IP", required => 1 ); $np->add_arg( spec => "port|p=i", help => "portnumber", default => 161 ); $np->add_arg( spec => "retries|T=i", help => "SNMP retries on error, default: %s", default => 1 ); $np->add_arg( spec => "unit|i=s", help => "unit for output and thresholds (KB|MB|GB), default: %s", default => "MB" ); # snmp v1/v2c $np->add_arg( spec => "snmpv1|1", help => "use SNMP version 1" ); $np->add_arg( spec => "snmpv2c|2", help => "use SNMP version 2c" ); $np->add_arg( spec => "community|c=s", help => "SNMPv1/SNMPv2c community name, default: %s", default => "public" ); # snmp v3 $np->add_arg( spec => "snmpv3|3", help => "use SNMP version 3" ); $np->add_arg( spec => "username|u=s", help => "SNMPv3 username" ); $np->add_arg( spec => "authprotocol|a=s", help => "SNMPv3 authentication protocol (md5|sha), default: %s", default => "md5" ); $np->add_arg( spec => "authpassword|A=s", help => "SNMPv3 authentication password" ); $np->add_arg( spec => "privprotocol|x=s", help => "SNMPv3 privacy protocol (des|aes), default: %s", default => "des" ); $np->add_arg( spec => "privpassword|X=s", help => "SNMPv3 privacy password" ); $np->add_arg( spec => "contextengineid|E=s", help => "SNMPv3 context engine ID" ); $np->add_arg( spec => "contextname|n=s", help => "SNMPv3 context name" ); # thresholds $np->add_arg( spec => "totalavail-warning|m=s", help => "Warning threshold for the total memory (real+swap) available, default: %s", label => [ "FLOAT:FLOAT" ], default => "500:" ); $np->add_arg( spec => "totalavail-critical|M=s", help => "Critical threshold for the total memory (real+swap) available, default: %s", label => [ "FLOAT:FLOAT" ], default => "200:" ); $np->add_arg( spec => "realavail-warning|r=s", help => "Warning threshold for the real memory available (free+buffer+cache), default: %s", label => [ "FLOAT:FLOAT" ], default => "200:" ); $np->add_arg( spec => "realavail-critical|R=s", help => "Critical threshold for the real memory available (free+buffer+cache), default: %s", label => [ "FLOAT:FLOAT" ], default => "50:" ); # parse arguments $np->getopts; ############ check & handle the unit parameter ############ my $unitstr; my $unitdiv; if (uc($np->opts->get("unit")) eq "KB") { $unitstr="KB"; $unitdiv=1; } elsif (uc($np->opts->get("unit")) eq "MB") { $unitstr="MB"; $unitdiv=1024; } elsif (uc($np->opts->get("unit")) eq "GB") { $unitstr="GB"; $unitdiv=1024*1024; } else { $np->nagios_die("illegal unit requested"); } ############ sanity-check the snmp-version ############ my $snmpversion=undef; if ($np->opts->get("snmpv1")) { $snmpversion=1; } if ($np->opts->get("snmpv2c")) { if (defined $snmpversion) { $np->nagios_die("you can only define one SNMP version"); } else { $snmpversion=2; } } if ($np->opts->get("snmpv3")) { if (defined $snmpversion) { $np->nagios_die("you can only define one SNMP version"); } else { $snmpversion=3; } } if (not defined $snmpversion) { # snmp default version $snmpversion=2; } ############ create the SNMP session ############ my %snmpsessionparam = ( -hostname => $np->opts->get("hostname"), -port => $np->opts->get("port"), -version => $snmpversion, -timeout => $np->opts->get("timeout"), -retries => $np->opts->get("retries"), ); my %snmprequestparam = (); if ($snmpversion == 1 || $snmpversion == 2) { $snmpsessionparam{-community}=$np->opts->get("community"); } else { $snmpsessionparam{-username}=$np->opts->get("username"); if (defined $np->opts->get("authpassword")) { $snmpsessionparam{-authprotocol}=$np->opts->get("authprotocol"); $snmpsessionparam{-authpassword}=$np->opts->get("authpassword"); } if (defined $np->opts->get("privpassword")) { $snmpsessionparam{-privprotocol}=$np->opts->get("privprotocol"); $snmpsessionparam{-privpassword}=$np->opts->get("privpassword"); } if (defined $np->opts->get("contextname")) { $snmprequestparam{-contextname}=$np->opts->get("contextname"); } if (defined $np->opts->get("contextengineid")) { $snmprequestparam{-contextengineid}=$np->opts->get("contextengineid"); } } ($np->opts->get("verbose") > 1) && print Data::Dumper->Dump([\%snmpsessionparam], [qw(snmp_session_data)]); my ($session,$snmperror)=Net::SNMP->session(%snmpsessionparam); if (!defined $session) { $np->nagios_die("Error opening SNMP session: $snmperror"); } ############ prepare & execute the snmp request ############ my $oid_memTotalSwap = "1.3.6.1.4.1.2021.4.3.0"; my $oid_memAvailSwap = "1.3.6.1.4.1.2021.4.4.0"; my $oid_memTotalReal = "1.3.6.1.4.1.2021.4.5.0"; my $oid_memAvailReal = "1.3.6.1.4.1.2021.4.6.0"; my $oid_memBuffer = "1.3.6.1.4.1.2021.4.14.0"; my $oid_memCached = "1.3.6.1.4.1.2021.4.15.0"; my $oid_ssSwapIn = "1.3.6.1.4.1.2021.11.3.0"; my $oid_ssSwapOut = "1.3.6.1.4.1.2021.11.4.0"; my $oid_intranator_swap_warning = "1.3.6.1.4.1.30475.1.1.3"; # we really need these oids to complete the check my @essential_oidlist = ($oid_memTotalSwap, $oid_memAvailSwap, $oid_memTotalReal, $oid_memAvailReal, $oid_memBuffer, $oid_memCached); # all oids, including the additional ones my @oidlist = (@essential_oidlist, $oid_ssSwapIn, $oid_ssSwapOut, $oid_intranator_swap_warning); my %thisrequest=%snmprequestparam; $thisrequest{-varbindlist}=\@oidlist; ($np->opts->get("verbose") > 2) && print Data::Dumper->Dump([\%thisrequest], [qw(snmp_request_data)]); my $result = $session->get_request(%thisrequest); if (!defined $result) { $snmperror=$session->error; $session->close(); $np->nagios_die("Error in SNMP request: $snmperror"); } ($np->opts->get("verbose") > 0) && print Data::Dumper->Dump([$result], [qw(snmp_result)]); $session->close(); ############ check if the essential oids are there ############ foreach my $oid (@essential_oidlist) { if (!defined $result->{$oid} || $result->{$oid} eq "noSuchObject") { $np->nagios_die("Essential OID $oid missing in result"); } } ############ interpret the results ############ # use only OIDs listed as essential here! my $realmem=$result->{$oid_memTotalReal}; my $realavail=$result->{$oid_memAvailReal}+$result->{$oid_memBuffer}+$result->{$oid_memCached}; my $swap=$result->{$oid_memTotalSwap}; my $swapused=$swap-$result->{$oid_memAvailSwap}; my $totalavail=$realavail+$result->{$oid_memAvailSwap}; my $realpercent=sprintf("%.0f",($realavail/$realmem)*100); my $totalpercent=sprintf("%.0f",($totalavail/($realmem+$swap))*100); my $swappercent=sprintf("%.0f",($swapused/$swap)*100); ############ convert the results to the desired unit ############ my @resultvar=(\$realmem, \$realavail, \$swap, \$swapused, \$totalavail); foreach my $varref (@resultvar) { $$varref/=$unitdiv; } ############ check the thresholds ############ # do this BEFORE the rounding my @results = (); push (@results, $np->check_threshold( check => $totalavail, warning => $np->opts->get("totalavail-warning"), critical => $np->opts->get("totalavail-critical") )); push (@results, $np->check_threshold( check => $realavail, warning => $np->opts->get("realavail-warning"), critical => $np->opts->get("realavail-critical") )); ############ rounding ############ # show decimals only if value less than limit foreach my $varref (@resultvar) { if ($$varref < 20) { $$varref=sprintf("%.2f",$$varref) } else { $$varref=sprintf("%.0f",$$varref) } } ############ output the performance data ############ $np->add_perfdata( label => "total_avail", value => $totalavail, uom => $unitstr, warning => $np->opts->get("totalavail-warning"), critical => $np->opts->get("totalavail-critical"), min => 0, max => $swap+$realmem ); $np->add_perfdata( label => "real_avail", value => $realavail, uom => $unitstr, warning => $np->opts->get("realavail-warning"), critical => $np->opts->get("realavail-critical"), min => 0, max => $realmem ); $np->add_perfdata( label => "swap_used", value => $swapused, uom => $unitstr, min => 0, max => $swap ); ############ compose message ############ $np->nagios_exit( $np->max_state(@results), "Real av: $realavail $unitstr ($realpercent%), Total av: $totalavail $unitstr ($totalpercent%), Swapped: $swapused $unitstr ($swappercent%)", );