#!/usr/bin/perl #/****************************************************************************** # * # * CHECK_F5_Nodes # * check-F5-nodes nagios plugin to monitor F5 BigIP nodes # * # * Program: Linux plugin for Nagios # * License: GPL # * Copyright (c) for all changes 2018- Martin Fuerstenau (martin.fuerstenau@oce.com) # * Portions copyright (c) 2009- Victor Ruiz (vruiz@adif.es) # * # * Description: # * # * This software checks some OID's from F5-BIGIP-LOCAL-MIB # * ltmNodes branch with nodes related objects # * # * This plugin is based on check_pool_members which is based on the pool # * member plugin of Victor Ruiz # * # * 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. # * # *****************************************************************************/ # # - 9 Feb 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.4'; my $ltmNodeAddrStatusAvailState = $baseoid . '.3.2.1.3'; my $ltmNodeAddrStatusEnabledState = $baseoid . '.3.2.1.3'; my $blacklist; # Contains the blacklist my $whitelist; # Contains the whitelist my $isregexp; # treat names, blacklist and whitelists as regexp my $ignored_nodes; # Blacklist: Names of ignored nodes. my $checked_nodes; # Whitelist: Names of ignored nodes. 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 %NodeMbrStatus_Table; # Hash to store node names as key and member status and # member enable state as values my $NodeEnabledStatus; # Stores the node member enabled state my $NodeStatus; # Stores the node member state my $NodeName; # Stores the node name my $NodeStatusKey; # Stores the key while processing %NodeMbrStatus_Table my $NodeStatusVal; # Stores the value while processing %NodeMbrStatus_Table my $crit_nodes = ""; my $warn_nodes = ""; 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 node indicated in color. # none - error; # green - available in some capacity; # yellow - not currently available; # red - not available; # blue - availability is unknown; # gray - unlicens my %ltmNodeStatusAvailState2Text = ( 0 => 'none', 1 => 'green', 2 => 'yellow', 3 => 'red', 4 => 'blue', 5 => 'gray', ); # The activity status of the specified node addressr, as specified # by the user. my %ltmNodeStatusEnabledState2Text = ( 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 => $ltmNodeAddrStatusAvailState, -maxrepetitions => 0 ); # Getting the node status. Due to the fact that the node name is stored as part # of the OID as ASCII code we can use a little trick and extract # it # # 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 # NodeName 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/^$ltmNodeAddrStatusAvailState\.//; # 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 = $ltmNodeAddrStatusEnabledState . "." . $snmp_result_key; $NodeEnabledStatus = $snmp_session->get_request( -varbindlist => ["$tmp_oid"] ); if (defined($$NodeEnabledStatus{$tmp_oid})) { $NodeEnabledStatus = $$NodeEnabledStatus{$tmp_oid}; } else { print "Critical! No Status(Enabled) received!"; exit 2; } # First two nummbers follow by a dot have to be eliminate # Don't know what it represents $snmp_result_key =~ s/^..\.//; # 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/%.*$//; # Filling the new hash $NodeMbrStatus_Table{ $tmp } = "$snmp_result_value:$NodeEnabledStatus"; } # OK - ready with snmp stuff $snmp_session->close; foreach $NodeStatusKey (sort keys %NodeMbrStatus_Table) { $NodeStatusVal = $NodeMbrStatus_Table{$NodeStatusKey}; $NodeName = $NodeStatusKey; $NodeStatus = $NodeStatusVal; $NodeStatus =~ s/:.*$//; $NodeEnabledStatus = $NodeStatusVal; $NodeEnabledStatus =~ s/^.*://; if (defined($whitelist)) { if (isnotwhitelisted(\$whitelist, $isregexp, $NodeName)) { next; } else { if ($checked_nodes !~ m/$NodeName/) { $checked_nodes = $checked_nodes . " " . $NodeName . $multiline; } } } if (defined($blacklist)) { if (isblacklisted(\$blacklist, $isregexp, $NodeName)) { if ($ignored_nodes !~ m/$NodeName/) { $ignored_nodes = $ignored_nodes . " " . $NodeName . $multiline; } next; } } if ( $NodeEnabledStatus == 0) { if ( $NodeStatus == 0) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_nodes = $warn_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } if ( $NodeStatus == 2) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_nodes = $warn_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } if ( $NodeStatus == 3) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_nodes = $warn_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } if ( $NodeStatus == 4) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_nodes = $warn_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } if ( $NodeStatus == 5) { $actual_exit_state = 2; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_nodes = $warn_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } } if ( $NodeEnabledStatus == 1) { if ( $NodeStatus == 0) { $actual_exit_state = 2; $exit_state = check_state($exit_state, $actual_exit_state); $crit_nodes = $crit_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } if ( $NodeStatus == 2) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_nodes = $warn_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } if ( $NodeStatus == 3) { $actual_exit_state = 2; $exit_state = check_state($exit_state, $actual_exit_state); $crit_nodes = $crit_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } if ( $NodeStatus == 4) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_nodes = $warn_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } if ( $NodeStatus == 5) { $actual_exit_state = 2; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_nodes = $warn_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } } if ( $NodeEnabledStatus == 3) { if ( $NodeStatus == 0) { $actual_exit_state = 2; $exit_state = check_state($exit_state, $actual_exit_state); $crit_nodes = $crit_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } if ( $NodeStatus == 2) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_nodes = $warn_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } if ( $NodeStatus == 3) { $actual_exit_state = 2; $exit_state = check_state($exit_state, $actual_exit_state); $crit_nodes = $crit_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } if ( $NodeStatus == 4) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_nodes = $warn_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } if ( $NodeStatus == 5) { $actual_exit_state = 1; $warn_state =1; $exit_state = check_state($exit_state, $actual_exit_state); $warn_nodes = $warn_nodes . "Node:" . $NodeName . " - Status(Node):" . $ltmNodeStatusAvailState2Text{ $NodeStatus } . " - Status(Enabled):" . $ltmNodeStatusEnabledState2Text{ $NodeEnabledStatus } . $multiline; } } } if ( $exit_state == 0) { print "OK: No errors for nodes found."; } if ( $exit_state == 1) { print "Warnings found:" . $multiline; print "$warn_nodes\n"; } if ( $exit_state == 2) { print "Errors found:" . $multiline; print "$crit_nodes\n"; if (defined($warn_state)) { print $multiline . "Warnings found for:" . $multiline; print "$warn_nodes\n"; } } if (defined($whitelist)) { print "Nodes checked:" . $multiline; print "$checked_nodes"; } if (defined($blacklist)) { print "Nodes ignored: " . $multiline; print "$ignored_nodes"; } 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 nodes.In case of a blacklist\n"; print " all blacklisted nodes will not be checked.\n"; print " Nodes filtered out by blacklist\n"; print " will be listed as ignored nodes.\n"; print " -W, --include= Whitelist nodes. In case of a whitelist\n"; print " only whitelisted nodes will be checked.\n"; print " Nodes checked will be listed\n"; print " in output as checked nodes.\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"; }