#!/usr/bin/perl #/****************************************************************************** # * # * check-F5-pools nagios plugin to monitor F5 BigIP pools # * # * Program: Linux plugin for Nagios # * License: GPL # * Copyright (c) 2009- Victor Ruiz (vruiz@adif.es) # * Copyright (c) for all changes 2018- Martin Fuerstenau (martin.fuerstenau@oce.com) # * # * Description: # * # * This software checks some OID's from F5-BIGIP-LOCAL-MIB # * ltmPoolStatus branch with pool related objects # * # * License Information: # * # * 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. # * # * You should have received a copy of the GNU General Public License # * along with this program; if not, write to the Free Software # * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # * # *****************************************************************************/ # # - 2009 Victor Ruiz # - Version 0.9 # # - 09 Jan 2018 M.Fuerstenau # - Version 1.0 # - reformatted code for better readability # - Changed Getopt::Std into Getopt::Long # - Changed -h to -H and -c to -C because upper case characters are much more # common for plugins. -h ist commonly used for help. # - All variable defintions at the beginning of the script. # - Removed unused parts # - Bugfix: Unknown has now a returncode of 3 and not -1. Fixed. # - Bugfix: Handing over $status to subroutine ended in a Hash instead of a variable. Fixed # - Added multiline output # - Enhenced buffer for NET::SNMP (-maxmsgsize). Default was to small # - --maxmsgsize Message buffer size adjustible # - Added whitelist. This will set a filter for monitored pools so that not # all pools will be listed. Whitelisted pools will be listed in output. # - Added blacklist to ignore pools. Pools filtered out by blacklist # will be listed as ignored pools. # - Added --full for full output of all pools. # # - 23 Jan 2018 M.Fuerstenau # - Version 1.1 # - Fixed exit on SNMP error or empty result. A linefeed (\n) # doesn't make sense because the error message wouldn't be displayed # in Nagios status overview use strict; use Net::SNMP qw(:snmp); use Getopt::Long; use File::Basename; # Let's catch some signals # Handle SIGALRM (timeout triggered by alarm() call) $SIG{ALRM} = 'catch_alarm'; $SIG{INT} = 'catch_intterm'; $SIG{TERM} = 'catch_intterm'; #--- Start presets and declarations ------------------------------------- my $ProgName = basename($0); # Name of the program my $version="1.1.0"; # Program version my $hostname; # Host name my $community; # SNMP community string my $timeout = 10; # SNMP Timeout my $timeout_alarm; # Timeout for alarm() my $status = 0; # Returncode my $multiline; # Multiline output in overview. This mean technically that # a multiline output uses a HTML
for the GUI instead of # Be aware that your messing connections (email, SMS...) must use # a filter to file out the
. A sed oneliner like the following # will do the job: # sed 's/<[^<>]*>//g' my $multiline_def="\n"; # Default for $multiline; my %ltmPoolStatusTable; my $PoolName; # Stores pools name in foreach loops my $oid; # Stores OID in foreach loops my $baseoid='.1.3.6.1.4.1.3375.2.2.5'; my $ltmPoolStatus = $baseoid . '.5'; my $ltmPoolStatusNumber = $baseoid . '.5.1.0'; my $ltmPoolStatusName = $baseoid . '.5.2.1.1'; my $ltmPoolStatusAvailState = $baseoid . '.5.2.1.2'; my $ltmPoolStatusEnabledState = $baseoid . '.5.2.1.3'; my $ltmPoolStatusDetailReason = $baseoid . '.5.2.1.5'; my %ltmPoolMbrStatusTable; my $ltmPoolMemberStatus = $baseoid . '.6'; my $ltmPoolMbrStatusNumber = $baseoid . '.6.1.0'; my $ltmPoolMbrStatusPoolName = $baseoid . '.6.2.1.1'; my $ltmPoolMbrStatusAvailState = $baseoid . '.6.2.1.5'; my $ltmPoolMbrStatusEnabledState = $baseoid . '.6.2.1.6'; my $ltmPoolMbrStatusDetailReason = $baseoid . '.6.2.1.8'; my $NoA; # Number of arguments my $snmp_session; # Store snmp session my $snmp_error; # Error when openeing a session my $result; # Stores result from request my $blacklist; # Contains the blacklist my $whitelist; # Contains the whitelist my $isregexp; # treat names, blacklist and whitelists as regexp my $full; # List all pools my $maxmsgsize; # Messagebuffer for SNMP request. Can be overwritten my $maxmsgsize_def=5000; # Default size messagebuffer. my $oids_cnt = 0; my %hiddenStrings; my $mbrs_cnt = 0; my %pool_enabled_members; my $enabled_pools_cnt = 0; # Number of enabled pools. my $enabled_pools = ""; # Names of enabled pools. my $disabled_pools_cnt = 0; # Number of disabled pools. my $disabled_pools = ""; # Names of disabled pools. my $available_pools_cnt = 0; # Number of available pools. my $available_pools; # Names of available pools. my $unavailable_pools_cnt = 0; # Number of unavailable pools. my $unavailable_pools; # Names of unavailable pools. my $ignored_pools_cnt = 0; # Number of ignored pools. my $ignored_pools; # Names of ignored pools. my $counter; my $help; my $table; my $OID_base; my $nextoid; #--- End presets -------------------------------------------------------- # First we have to fix the number of arguments $NoA=$#ARGV; # Right number of arguments (therefore NoA :-)) ) if ( $NoA == -1 ) { usage(); exit 1; } Getopt::Long::Configure('bundling'); GetOptions ("H=s" => \$hostname, "hostname=s" => \$hostname, "C=s" => \$community, "community=s" => \$community, "t=s" => \$timeout, "timeout=s" => \$timeout, "multiline" => \$multiline, "maxmsgsize" => \$maxmsgsize, "B=s" => \$blacklist, "exclude=s" => \$blacklist, "W=s" => \$whitelist, "include=s" => \$whitelist, "isregexp" => \$isregexp, "full" => \$full, "h" => \$help, "help" => \$help, "V" => \$version, "version" => \$version); # Set timeout for alarm() $timeout_alarm = $timeout + 30; alarm ($timeout_alarm); # Several checks to check parameters if ($help) { help(); exit 0; } # Multiline output in GUI overview? if (defined($multiline)) { $multiline = "
"; } else { $multiline = $multiline_def; } # So if we have a whitelist we set output to full. Otherwise we woudln't know # what is been check if (defined($whitelist)) { $full = 1; } # Set message buffer max size if (!defined($maxmsgsize)) { $maxmsgsize = $maxmsgsize_def; } ($snmp_session, $snmp_error) = Net::SNMP->session(-hostname => $hostname, -version => 'snmpv2c', -nonblocking => 1, -community => $community, -port => 161, -timeout => $timeout, -maxmsgsize => $maxmsgsize ); if (!defined($snmp_session)) { print "ERROR: $snmp_error"; exit 3; } $result = $snmp_session->get_bulk_request(-callback => [\&table_cb, \%ltmPoolStatusTable, $ltmPoolStatus], -maxrepetitions => 10, -varbindlist => [$ltmPoolStatus] ); if (!defined($result)) { print "ERROR:" . $snmp_session->error; $snmp_session->close; exit 3; } $result = $snmp_session->get_bulk_request(-callback => [\&table_cb, \%ltmPoolMbrStatusTable, $ltmPoolMemberStatus], -maxrepetitions => 10, -varbindlist => [$ltmPoolMemberStatus] ); if (!defined($result)) { print "ERROR:" . $snmp_session->error; $snmp_session->close; exit 3; } snmp_dispatcher(); $snmp_session->close; foreach $oid (oid_lex_sort(keys(%ltmPoolStatusTable))) { if ( oid_base_match($ltmPoolStatusName, $oid) ) { $oids_cnt++; $hiddenStrings{$ltmPoolStatusTable{$oid}} = substr($oid, length($ltmPoolStatusName)); } else { if ( $oids_cnt >= $ltmPoolStatusTable{$ltmPoolStatusNumber} ) { last; } } } foreach $oid (oid_lex_sort(keys(%ltmPoolMbrStatusTable))) { if ( oid_base_match($ltmPoolMbrStatusEnabledState, $oid) ) { $mbrs_cnt++; if ( $ltmPoolMbrStatusTable{ $oid } == 1 ) { $counter = $pool_enabled_members{ $ltmPoolMbrStatusTable{ $ltmPoolMbrStatusPoolName . substr($oid, length($ltmPoolMbrStatusEnabledState))}}; if (defined($counter)) { $counter++; $pool_enabled_members{ $ltmPoolMbrStatusTable{ $ltmPoolMbrStatusPoolName . substr($oid, length($ltmPoolMbrStatusEnabledState))}} = $counter; } else { $pool_enabled_members{ $ltmPoolMbrStatusTable{ $ltmPoolMbrStatusPoolName . substr($oid, length($ltmPoolMbrStatusEnabledState))}} = 1; } } } else { if ( $mbrs_cnt >= $ltmPoolMbrStatusTable{$ltmPoolMbrStatusNumber} ) { last; } } } foreach $PoolName (oid_lex_sort(keys(%hiddenStrings))) { if ( $ltmPoolStatusTable{$ltmPoolStatusEnabledState . $hiddenStrings{$PoolName}} == 1) { if (defined($whitelist)) { if (isnotwhitelisted(\$whitelist, $isregexp, $PoolName)) { next; } else { $enabled_pools_cnt++; $enabled_pools = $enabled_pools . " " . $PoolName . $multiline; } } else { $enabled_pools_cnt++; $enabled_pools = $enabled_pools . " " . $PoolName . $multiline; } if (defined($blacklist)) { if (isblacklisted(\$blacklist, $isregexp, $PoolName)) { $ignored_pools_cnt++; $ignored_pools = $ignored_pools . " " . $PoolName . $multiline; next; } } if ( $ltmPoolStatusTable{$ltmPoolStatusAvailState . $hiddenStrings{$PoolName}} == 1 ) { $available_pools_cnt++; $available_pools = $available_pools . " " . $PoolName . $multiline; } else { $unavailable_pools_cnt++; if ( $pool_enabled_members{ $PoolName } > 0 ) { $unavailable_pools = $unavailable_pools . "'" . $PoolName . "' (" . $ltmPoolStatusTable{$ltmPoolStatusDetailReason . $hiddenStrings{$PoolName}} . ") " . $multiline; $status = 2; } else { $unavailable_pools = $unavailable_pools . "'" . $PoolName . "' ( All pool-members disabled ) " . $multiline; if ($status == 0) { $status = 1; } } } } else { $disabled_pools_cnt++; $disabled_pools = $disabled_pools . " " . $PoolName . $multiline; } } if ( !defined ($ltmPoolStatusTable{$ltmPoolStatusNumber}) ) { $status = 2; } # ---- Start creating the output ----------------------------------------- if (defined($whitelist)) { print "Pools(".$ltmPoolStatusTable{$ltmPoolStatusNumber}.")
Whitelisted only: "; } else { print "Pools(".$ltmPoolStatusTable{$ltmPoolStatusNumber}.")-"; } print "Enabled(" . $enabled_pools_cnt . ")-"; print "Disabled(" . $disabled_pools_cnt . ")-"; print "Available(" . $available_pools_cnt . ")-"; print "Unavailable(" . $unavailable_pools_cnt . ")-"; print "Ignored(" . $ignored_pools_cnt . ")"; if (defined($full)) { print $multiline . "Enabled pools:" . $multiline . $enabled_pools; } if ($disabled_pools_cnt > 0) { print $multiline . "Disabled pools:" . $multiline . $disabled_pools; } if (defined($full)) { print $multiline . "Available pools:" . $multiline . $available_pools; } if ($unavailable_pools_cnt > 0) { print $multiline . "Unavailable pools:" . $multiline . $unavailable_pools; } if ($ignored_pools_cnt > 0) { print $multiline . "Ignored pools:" . $multiline . $ignored_pools; } exit $status; # ---- Subroutines ------------------------------------------------------- # Catching some signals sub catch_alarm { print "UNKNOWN: Script timed out.\n"; exit 3; } sub catch_intterm { print "UNKNOWN: Script killed by monitor.\n"; exit 3; } sub table_cb { ($snmp_session, $table, $OID_base) = @_; if (!defined($snmp_session->var_bind_list)) { print "ERROR:" . $snmp_session->error; $status = 2; } else { # Loop through each of the OIDs in the response and assign # the key/value pairs to the anonymous hash that is passed # to the callback. Make sure that we are still in the table # before assigning the key/values. foreach $oid (oid_lex_sort(keys(%{$snmp_session->var_bind_list}))) { if (!oid_base_match($OID_base, $oid)) { $nextoid = undef; last; } $nextoid = $oid; $table->{$oid} = $snmp_session->var_bind_list->{$oid}; } # If $nextoid is defined we need to send another request # to get more of the table. if (defined($nextoid)) { $result = $snmp_session->get_bulk_request(-callback => [\&table_cb, $table, $OID_base], -maxrepetitions => 10, -varbindlist => [$nextoid] ); if (!defined($result)) { print "ERROR:" . $snmp_session->error; $status = 2; } } } } sub isblacklisted() { my ($blacklist_ref,$regexpflag,$candidate) = @_; my $ret = 0; my @blacklist; my $blacklist; my $hitcount = 0; if (!defined $$blacklist_ref) { return 0; } if ($regexpflag == 0) { $ret = grep(/$candidate/, $$blacklist_ref); } else { @blacklist = split(/,/, $$blacklist_ref); foreach $blacklist (@blacklist) { if ($candidate =~ m/$blacklist/) { $hitcount++; } } if ($hitcount >= 1) { $ret = 1; } } return $ret; } sub isnotwhitelisted() { my ($whitelist_ref,$regexpflag,$candidate) = @_; my $ret = 0; my @whitelist; my $whitelist; my $hitcount = 0; if (!defined $$whitelist_ref) { return $ret; } if ($regexpflag == 0) { $ret = ! grep(/$candidate/, $$whitelist_ref); } else { @whitelist = split(/,/, $$whitelist_ref); foreach $whitelist (@whitelist) { if ($candidate =~ m/$whitelist/) { $hitcount++; } } if ($hitcount == 0) { $ret = 1; } } return $ret; } sub usage() { print "\nUsage:\n"; print "$ProgName "; print "-H|--hostname= "; print "-C|--community= "; print "[--maxmsgsize] "; print "[-t|--timeout= timeout for snmp-response>] "; print "[-W|--include=] "; print "[-B, --exclude=] "; print "[--isregexp] "; print "[--multiline]\n\n"; print "or\n\n"; print "$ProgName -h\n\n"; } sub help() { usage(); print "\n"; print "Options are:\n"; print "\n"; print " -H, --hostname= Hostname or IP address of the monitored\n"; print " system.\n"; print " -C, --community= SNMP community string of the monitored\n"; print " system.\n"; print " --maxmsgsize Message buffer size for SNMP request.\n"; print " Default size of 5000 can be set higher\n"; print " if needed.\n"; print " -t, --timeout= SNMP timeout for response.\n"; print " --full Full output - lists all pools and their\n"; print " status.\n"; print " -B, --exclude= Blacklist pools.In case of a blacklist all\n"; print " blacklistedlisted enabled pools are listed\n"; print " as ignored. Otherwise you won't know what\n"; print " you are checking.\n"; print " -W, --include= Whitelist pools. In case of a whitelist all\n"; print " whitelisted enabled pools are listed.Otherwise\n"; print " you won't know what you are checking.\n"; print " --isregexp Whether to treat blacklist and whitelist as\n"; print " regexp.\n"; print " --multiline Multiline output in overview. This means\n"; print " technically that a multiline output uses\n"; print " a HTML
for the GUI instead of\\n. Be\n"; print " aware that your messing connections (email,\n"; print " SMS...) must use a filter to file out the
.\n"; print " A sed oneliner like the following the job:\n"; print "\n"; print " sed 's/<[^<>]*>//g'\n"; print "\n"; }