#!/usr/bin/perl #/****************************************************************************** # * # * CHECK_F5_POOL_MEMBERS # * check-F5-poolsmembers nagios plugin to monitor F5 BigIP pool members # * # * 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 # * ltmPools branch with pool members 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 # # - 29 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. # - 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 # - Added whitelist. This will set a filter for monitored pools so that not # all pools will be listed. Pools checked will be listed in output as # checked pools.. # - Added blacklist to ignore pools. Pools filtered out by blacklist # will be listed as ignored pools. # - Rewritten complete SNMP and outpu part. Some of the stuff used was replaced in SNMP output. # - 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 ------------------------------------- # 1. Define variables my $ProgName = basename($0); # Name of the program my $version="1.0.0"; # Program version my $hostname; # Host name my $community; # SNMP community string my $timeout = 10; # SNMP Timeout my $timeout_alarm; # Timeout for alarm() 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 $baseoid='.1.3.6.1.4.1.3375.2.2.5'; my $ltmPoolMbrStatusAvailState = $baseoid . '.6.2.1.5'; my $ltmPoolMbrStatusEnabledState = $baseoid . '.6.2.1.6'; my $blacklist; # Contains the blacklist my $whitelist; # Contains the whitelist my $isregexp; # treat names, blacklist and whitelists as regexp my $ignored_pools; # Blacklist: Names of ignored pools. my $checked_pools; # Whitelist: Names of ignored pools. my $NoA; # Number of arguments my $snmp_session; # Store snmp session my $snmp_error; # Error when openeing a session my $snmp_result; # Stores result from request in Hash reference my $snmp_result_key; # Keys of the Hash reference my $snmp_result_value; # Stores of the Hash reference my %PoolMbrStatus_Table; # Hash to store pool names and pool members names as key # and member status and member enable state as values my $PoolMbrEnabledStatus; # Stores the pool member enabled state my $PoolMbrStatus; # Stores the pool member state my $PoolName; # Stores the pool name my $PoolMbrName; # Stores the pool member name my $PoolMbrStatusKey; # Stores the key while processing %PoolMbrStatus_Table my $PoolMbrStatusVal; # Stores the value while processing %PoolMbrStatus_Table my $crit_members = ""; my $warn_members = ""; my $help; # Flag for help() my @tmp; # Temporary array for work my $tmp; # Temporary variable for work my $tmp_oid; # Temporary variable for storing an OID my $warn_state; # Used to display warning in case of critical too my $actual_exit_state = 0; # Exit state from actual check my $exit_state = 0; # Highest and final exit state # 2. Define hashes and arrays # The availability of the specified pool member indicated in color. # none - error; # green - available in some capacity; # yellow - not currently available; # red - not available; # blue - availability is unknown; # gray - unlicens my %ltmPoolMbrStatusAvailState2Text = ( 0 => 'none', 1 => 'green', 2 => 'yellow', 3 => 'red', 4 => 'blue', 5 => 'gray', ); # The activity status of the specified pool member, as specified # by the user. my %ltmPoolMbrStatusEnabledState2Text = ( 0 => 'none', 1 => 'enabled', 2 => 'disabled', 3 => 'disabledbyparent', ); #--- 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, "B=s" => \$blacklist, "exclude=s" => \$blacklist, "W=s" => \$whitelist, "include=s" => \$whitelist, "isregexp" => \$isregexp, "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; } ($snmp_session, $snmp_error) = Net::SNMP->session(-hostname => $hostname, -version => 2, -community => $community, -port => 161, -timeout => $timeout, ); if (!defined($snmp_session)) { print "ERROR: $snmp_error"; exit 3; } $snmp_result = $snmp_session->get_table(-baseoid => $ltmPoolMbrStatusAvailState, -maxrepetitions => 0 ); # Getting the pool member status. Due to the fact that the pool name and the member # is stored as part of the OID as ASCII code we can use a little trick and extract # it. For a some unknown reason we have different not printable non ASCII characters # between the OID stored in $ltmPoolMbrStatusAvailState and the ASCII part we have # to eliminate. # # We also has to eliminate port numbers which can be interpreted as ASCII code. All # other port numbers will be eliminated automatically. # # By replacing the base OID (AvailState with EnabledState) we can get the Enabled state # with a get request. # # The results will be stored in a new hash in the following format: # # Key Value # PoolName:MemberName MemberState:MemberEnabled:State # # So we have all things we need foreach $snmp_result_key ( keys %$snmp_result) { $snmp_result_value = $$snmp_result{$snmp_result_key}; $snmp_result_key =~ s/^$ltmPoolMbrStatusAvailState\.//; # After eliminating the base oid we can get the enable status # by assembling a new OID to use a get request. This is more # efficient than getting a table $tmp_oid = $ltmPoolMbrStatusEnabledState . "." . $snmp_result_key; $PoolMbrEnabledStatus = $snmp_session->get_request( -varbindlist => ["$tmp_oid"] ); if (defined($$PoolMbrEnabledStatus{$tmp_oid})) { $PoolMbrEnabledStatus = $$PoolMbrEnabledStatus{$tmp_oid}; } else { print "Critical! No enabled status received!"; exit 2; } # First two nummbers follow by a dot have to be eliminate # Don't know what it represents $snmp_result_key =~ s/^..\.//; # Kill port numbers at the end $snmp_result_key =~ s/\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$//; # Convert it to an arry @tmp=split(/\./, $snmp_result_key); # And now we convert it to ASCII $tmp = pack("C*", @tmp); # And remove no printable characters $tmp =~ s/[^[:ascii:]]//g; # For members not stored with it's hostname # we have to filter out %number at the end of the IP address $tmp =~ s/%.*$//; # Now we have to add a unique seperator between the pool # and member name $tmp =~ s/pool.?\/Common/pool:\/Common/; # Filling the new hash $PoolMbrStatus_Table{ $tmp } = "$snmp_result_value:$PoolMbrEnabledStatus"; } # OK - ready with snmp stuff $snmp_session->close; foreach $PoolMbrStatusKey (sort keys %PoolMbrStatus_Table) { $PoolMbrStatusVal = $PoolMbrStatus_Table{$PoolMbrStatusKey}; $PoolName = $PoolMbrStatusKey; $PoolName =~ s/:.*$//; $PoolMbrName = $PoolMbrStatusKey; $PoolMbrName =~ s/^.*\///; $PoolMbrStatus = $PoolMbrStatusVal; $PoolMbrStatus =~ s/:.*$//; $PoolMbrEnabledStatus = $PoolMbrStatusVal; $PoolMbrEnabledStatus =~ s/^.*://; if (defined($whitelist)) { if (isnotwhitelisted(\$whitelist, $isregexp, $PoolName)) { next; } else { if ($checked_pools !~ m/$PoolName/) { $checked_pools = $checked_pools . " " . $PoolName . $multiline; } } } if (defined($blacklist)) { if (isblacklisted(\$blacklist, $isregexp, $PoolName)) { if ($ignored_pools !~ m/$PoolName/) { $ignored_pools = $ignored_pools . " " . $PoolName . $multiline; } next; } } if ( $PoolMbrEnabledStatus == 0) { if ( $PoolMbrStatus == 0) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_members = $warn_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } if ( $PoolMbrStatus == 2) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_members = $warn_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } if ( $PoolMbrStatus == 3) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_members = $warn_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } if ( $PoolMbrStatus == 4) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_members = $warn_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } if ( $PoolMbrStatus == 5) { $actual_exit_state = 2; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_members = $warn_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } } if ( $PoolMbrEnabledStatus == 1) { if ( $PoolMbrStatus == 0) { $actual_exit_state = 2; $exit_state = check_state($exit_state, $actual_exit_state); $crit_members = $crit_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } if ( $PoolMbrStatus == 2) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_members = $warn_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } if ( $PoolMbrStatus == 3) { $actual_exit_state = 2; $exit_state = check_state($exit_state, $actual_exit_state); $crit_members = $crit_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } if ( $PoolMbrStatus == 4) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_members = $warn_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } if ( $PoolMbrStatus == 5) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_members = $warn_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } } if ( $PoolMbrEnabledStatus == 3) { if ( $PoolMbrStatus == 0) { $actual_exit_state = 2; $exit_state = check_state($exit_state, $actual_exit_state); $crit_members = $crit_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } if ( $PoolMbrStatus == 2) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_members = $warn_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } if ( $PoolMbrStatus == 3) { $actual_exit_state = 2; $exit_state = check_state($exit_state, $actual_exit_state); $crit_members = $crit_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } if ( $PoolMbrStatus == 4) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_members = $warn_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } if ( $PoolMbrStatus == 5) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_members = $warn_members . "Member:" . $PoolMbrName . " Status:" . $ltmPoolMbrStatusAvailState2Text{ $PoolMbrStatus } . " Pool:" . $PoolName . " PoolStatus:" . $ltmPoolMbrStatusEnabledState2Text{ $PoolMbrEnabledStatus } . $multiline; } } } if ( $exit_state == 0) { print "OK: No errors for any pool members found."; } if ( $exit_state == 1) { print "Warnings found for:" . $multiline; print "$warn_members\n"; } if ( $exit_state == 2) { print "Errors found for:" . $multiline; print "$crit_members\n"; if (defined($warn_state)) { print $multiline . "Warnings found for:" . $multiline; print "$warn_members\n"; } } if (defined($whitelist)) { print "Pools checked:" . $multiline; print "$checked_pools"; } if (defined($blacklist)) { print "Pools ignored: " . $multiline; print "$ignored_pools"; } exit $exit_state; # ---- 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 check_state { if (grep { $_ == 2 } @_) { return 2; } if (grep { $_ == 1 } @_) { return 1; } if (grep { $_ == 3 } @_) { return 3; } if (grep { $_ == 0 } @_) { return 0; } return 3; } 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 "[-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 "Be aware: Members of disabled pools will not be checked!\n"; print"\n"; print " -H, --hostname= Hostname or IP address of the\n"; print " monitored system.\n"; print " -C, --community= SNMP community string of the\n"; print " monitored system.\n"; print " -t, --timeout= SNMP timeout for response.\n"; print " -B, --exclude= Blacklist pools.In case of a blacklist\n"; print " all members of blacklisted\n"; print " pools will not be checked.\n"; print " Pools filtered out by blacklist\n"; print " will be listed as ignored pools.\n"; print " -W, --include= Whitelist pools. In case of a whitelist\n"; print " only members of whitelisted\n"; print " enabled pools will be checked.\n"; print " Pools checked will be listed\n"; print " in output as checked pools.\n"; print " --isregexp Whether to treat blacklist and whitelist\n"; print " as 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"; print " Be aware that your messing connections\n"; print " (email, SMS...) must use a filter to file\n"; print " out the
. A sed oneliner like the\n"; print " following will do the job:\n"; print "\n"; print " sed 's/<[^<>]*>//g'\n"; print "\n"; }