2021/monitoring/icinga2/scripts/check_snmp_cisco_poe.pl

478 lines
16 KiB
Perl
Raw Permalink Normal View History

#!/usr/bin/perl
# ============================================================================
# ============================== INFO ========================================
# ============================================================================
# Version : 0.3
# Date : March 6 2019
# Author : Michiel Timmers ( michiel.timmers AT gmx.net) +Farid Joubbi
# Licence : GPL - summary below
#
# ============================================================================
# ============================== SUMMARY =====================================
# ============================================================================
#
# Check the PoE availability of a Cisco switch
# version 0.3 By farid@joubbi.se:
# - Added performace data
# - Small modifications of output
#
# version 0.2:
# - fix for Cisco bug CSCtl11469. Data is now collected via a snmpwalk
# - added support for stackble switches
#
# Check the http://exchange.nagios.org website for new versions.
# For comments, questions, problems and patches send me an
# e-mail (michiel.timmmers AT gmx.net).
#
# ============================================================================
# ============================== LICENCE =====================================
# ============================================================================
# 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 3 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, see <http://www.gnu.org/licenses/>
#
# ============================================================================
# ============================== HELP ========================================
# ============================================================================
# Help : ./check_snmp_cisco_poe.pl --help
#
# ============================================================================
use warnings;
use strict;
use Net::SNMP;
use Getopt::Long;
use Scalar::Util qw(looks_like_number);
#use lib "/usr/local/nagios/libexec";
#use utils qw(%ERRORS $TIMEOUT);
# ============================================================================
# ============================== NAGIOS VARIABLES ============================
# ============================================================================
my $TIMEOUT = 15; # This is the global script timeout, not the SNMP timeout
my %ERRORS = ('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
my @Nagios_state = ("UNKNOWN","OK","WARNING","CRITICAL"); # Nagios states coding
# ============================================================================
# ============================== OID VARIABLES ===============================
# ============================================================================
# System description
my $cisco_pethMainPseEntry_oid = "1.3.6.1.2.1.105.1.3.1.1"; # pethMainPseEntry
my $cisco_pethMainPsePower_oid = "1.3.6.1.2.1.105.1.3.1.1.2"; # pethMainPsePower
my $cisco_pethMainPseOperStatus_oid = "1.3.6.1.2.1.105.1.3.1.1.3"; # pethMainPseOperStatus
my $cisco_pethMainPseConsumptionPower_oid = "1.3.6.1.2.1.105.1.3.1.1.4"; # pethMainPseConsumptionPower
# ============================================================================
# ============================== GLOBAL VARIABLES ============================
# ============================================================================
my $Version = '0.3'; # Version number of this script
my $o_host = undef; # Hostname
my $o_community = undef; # Community
my $o_port = 161; # Port
my $o_help = undef; # Want some help ?
my $o_verb = undef; # Verbose mode
my $o_version = undef; # Print version
my $o_timeout = undef; # Timeout (Default 5)
my $o_version1 = undef; # Use SNMPv1
my $o_version2 = undef; # Use SNMPv2c
my $o_domain = undef; # Use IPv6
my $o_login = undef; # Login for SNMPv3
my $o_passwd = undef; # Pass for SNMPv3
my $v3protocols = undef; # V3 protocol list.
my $o_authproto = 'sha'; # Auth protocol
my $o_privproto = 'aes'; # Priv protocol
my $o_privpass = undef; # priv password
my $o_warning = undef; # Warning threshold
my $o_critical = undef; # Critical threshold
# ============================================================================
# ============================== SUBROUTINES (FUNCTIONS) =====================
# ============================================================================
# Subroutine: Print version
sub p_version {
print "check_snmp_cisco_poe version : $Version\n";
}
# Subroutine: Print Usage
sub print_usage {
print "Usage: $0 [-v] -H <host> [-6] -C <snmp_community> [-2] -w <warning threshold in Watt> -c <critical threshold in Watt> | (-l login -x passwd [-X pass -L <authp>,<privp>]) [-p <port>] [-t <timeout>] [-V]\n";
}
# Subroutine: Check number
sub isnnum { # Return true if arg is not a number
my $num = shift;
if ( $num =~ /^(\d+\.?\d*)|(^\.\d+)$/ ) { return 0 ;}
return 1;
}
# Subroutine: Set final status
sub set_status { # Return worst status with this order : OK, unknown, warning, critical
my $new_status = shift;
my $cur_status = shift;
if ($new_status == 1 && $cur_status != 2) {$cur_status = $new_status;}
if ($new_status == 2) {$cur_status = $new_status;}
if ($new_status == 3 && $cur_status == 0) {$cur_status = $new_status;}
return $cur_status;
}
# Subroutine: Check if SNMP table could be retrieved, otherwise give error
sub check_snmp_result {
my $snmp_table = shift;
my $snmp_error_mesg = shift;
# Check if table is defined and does not contain specified error message.
# Had to do string compare it will not work with a status code
if (!defined($snmp_table) && $snmp_error_mesg !~ /table is empty or does not exist/) {
printf("ERROR: ". $snmp_error_mesg . " : UNKNOWN\n");
exit $ERRORS{"UNKNOWN"};
}
}
# Subroutine: Print complete help
sub help {
print "\nSNMP Cisco SNMP PoE check plugin for Nagios\nVersion: ",$Version,"\n\n";
print_usage();
print <<EOT;
Options:
-v, --verbose
Print extra debugging information
-h, --help
Print this help message
-H, --hostname=HOST
Hostname or IPv4/IPv6 address of host to check
-6, --use-ipv6
Use IPv6 connection
-C, --community=COMMUNITY NAME
Community name for the host's SNMP agent
-w, --warning=WATT
Warning threshold in Watt
-c, --critical=WATT
Critical threshold in Watt
-1, --v1
Use SNMPv1
-2, --v2c
Use SNMPv2c (default)
-l, --login=LOGIN ; -x, --passwd=PASSWD
Login and auth password for SNMPv3 authentication
If no priv password exists, implies AuthNoPriv
-X, --privpass=PASSWD
Priv password for SNMPv3 (AuthPriv protocol)
-L, --protocols=<authproto>,<privproto>
<authproto> : Authentication protocol (md5|sha : default sha)
<privproto> : Priv protocole (des|aes : default aes)
-P, --port=PORT
SNMP port (Default 161)
-t, --timeout=INTEGER
Timeout for SNMP in seconds (Default: 5)
-V, --version
Prints version number
Notes:
- Check the http://exchange.nagios.org website for new versions.
- For questions, problems and patches send me an e-mail (michiel.timmmers AT gmx.net).
EOT
}
# Subroutine: Verbose output
sub verb {
my $t=shift;
print $t,"\n" if defined($o_verb);
}
# Subroutine: Verbose output
sub check_options {
Getopt::Long::Configure ("bundling");
GetOptions(
'v' => \$o_verb, 'verbose' => \$o_verb,
'h' => \$o_help, 'help' => \$o_help,
'H:s' => \$o_host, 'hostname:s' => \$o_host,
'p:i' => \$o_port, 'port:i' => \$o_port,
'C:s' => \$o_community, 'community:s' => \$o_community,
'l:s' => \$o_login, 'login:s' => \$o_login,
'x:s' => \$o_passwd, 'passwd:s' => \$o_passwd,
'X:s' => \$o_privpass, 'privpass:s' => \$o_privpass,
'L:s' => \$v3protocols, 'protocols:s' => \$v3protocols,
't:i' => \$o_timeout, 'timeout:i' => \$o_timeout,
'V' => \$o_version, 'version' => \$o_version,
'6' => \$o_domain, 'use-ipv6' => \$o_domain,
'1' => \$o_version1, 'v1' => \$o_version1,
'2' => \$o_version2, 'v2c' => \$o_version2,
'w:i' => \$o_warning, 'warning:i' => \$o_warning,
'c:i' => \$o_critical, 'critical:i' => \$o_critical
);
# Basic checks
if (defined($o_timeout) && (isnnum($o_timeout) || ($o_timeout < 2) || ($o_timeout > 60))) {
print "Timeout must be >1 and <60 !\n";
print_usage();
exit $ERRORS{"UNKNOWN"};
}
if (!defined($o_timeout)) {
$o_timeout=5;
}
if (defined ($o_help) ) {
help();
exit $ERRORS{"UNKNOWN"};
}
if (defined($o_version)) {
p_version();
exit $ERRORS{"UNKNOWN"};
}
# check host and filter
if ( ! defined($o_host) ) {
print_usage();
exit $ERRORS{"UNKNOWN"};
}
# Check IPv6
if (defined ($o_domain)) {
$o_domain="udp/ipv6";
} else {
$o_domain="udp/ipv4";
}
# Check SNMP information
if ( !defined($o_community) && (!defined($o_login) || !defined($o_passwd)) ){
print "Put SNMP login info!\n";
print_usage();
exit $ERRORS{"UNKNOWN"};
}
if ((defined($o_login) || defined($o_passwd)) && (defined($o_community) || defined($o_version2)) ){
print "Can't mix SNMP v1,v2c,v3 protocols!\n";
print_usage();
exit $ERRORS{"UNKNOWN"};
}
# Check SNMPv3 information
if (defined ($v3protocols)) {
if (!defined($o_login)) {
print "Put SNMP V3 login info with protocols!\n";
print_usage();
exit $ERRORS{"UNKNOWN"};
}
my @v3proto=split(/,/,$v3protocols);
if ((defined ($v3proto[0])) && ($v3proto[0] ne "")) {
$o_authproto=$v3proto[0];
}
if (defined ($v3proto[1])) {
$o_privproto=$v3proto[1];
}
if ((defined ($v3proto[1])) && (!defined($o_privpass))) {
print "Put SNMP v3 priv login info with priv protocols!\n";
print_usage();
exit $ERRORS{"UNKNOWN"};
}
}
if ( ! defined($o_warning) ) {
print_usage();
exit $ERRORS{"UNKNOWN"};
}
if ( ! defined($o_critical) ) {
print_usage();
exit $ERRORS{"UNKNOWN"};
}
}
# ============================================================================
# ============================== MAIN ========================================
# ============================================================================
check_options();
# Check gobal timeout if SNMP screws up
if (defined($TIMEOUT)) {
verb("Alarm at ".$TIMEOUT." + ".$o_timeout);
alarm($TIMEOUT+$o_timeout);
} else {
verb("no global timeout defined : ".$o_timeout." + 15");
alarm ($o_timeout+15);
}
# Report when the script gets "stuck" in a loop or takes to long
$SIG{'ALRM'} = sub {
print "UNKNOWN: Script timed out\n";
exit $ERRORS{"UNKNOWN"};
};
# Connect to host
my ($session,$error);
if (defined($o_login) && defined($o_passwd)) {
# SNMPv3 login
verb("SNMPv3 login");
if (!defined ($o_privpass)) {
# SNMPv3 login (Without encryption)
verb("SNMPv3 AuthNoPriv login : $o_login, $o_authproto");
($session, $error) = Net::SNMP->session(
-domain => $o_domain,
-hostname => $o_host,
-version => 3,
-username => $o_login,
-authpassword => $o_passwd,
-authprotocol => $o_authproto,
-timeout => $o_timeout
);
} else {
# SNMPv3 login (With encryption)
verb("SNMPv3 AuthPriv login : $o_login, $o_authproto, $o_privproto");
($session, $error) = Net::SNMP->session(
-domain => $o_domain,
-hostname => $o_host,
-version => 3,
-username => $o_login,
-authpassword => $o_passwd,
-authprotocol => $o_authproto,
-privpassword => $o_privpass,
-privprotocol => $o_privproto,
-timeout => $o_timeout
);
}
} else {
if ((defined ($o_version2)) || (!defined ($o_version1))) {
# SNMPv2 login
verb("SNMP v2c login");
($session, $error) = Net::SNMP->session(
-domain => $o_domain,
-hostname => $o_host,
-version => 2,
-community => $o_community,
-port => $o_port,
-timeout => $o_timeout
);
} else {
# SNMPv1 login
verb("SNMP v1 login");
($session, $error) = Net::SNMP->session(
-domain => $o_domain,
-hostname => $o_host,
-version => 1,
-community => $o_community,
-port => $o_port,
-timeout => $o_timeout
);
}
}
# Check if there are any problems with the session
if (!defined($session)) {
printf("ERROR opening session: %s.\n", $error);
exit $ERRORS{"UNKNOWN"};
}
my $exit_val=undef;
# ============================================================================
# ============================== Cisco - PoE =================================
# ============================================================================
# Define variables
my $output = "";
my $output_pd = "";
my $final_status = 0;
my $result_t;
my $index;
my @temp_oid;
my ($pethMainPsePower,$pethMainPseOperStatus,$pethMainPseConsumptionPower,$module)=(undef,undef,undef,undef);
# Get SNMP table(s) and check the result
my $cisco_pethMainPseEntry = $session->get_table(Baseoid => $cisco_pethMainPseEntry_oid);
&check_snmp_result($cisco_pethMainPseEntry,$session->error);
if (defined($cisco_pethMainPseEntry)) {
foreach my $key ( keys %$cisco_pethMainPseEntry) {
if ($key =~ /$cisco_pethMainPseOperStatus_oid/) {
$key =~ s/$cisco_pethMainPseOperStatus_oid//;
$module = substr $key, 1;
# Set the Pse variables
$pethMainPsePower = $$cisco_pethMainPseEntry{$cisco_pethMainPsePower_oid.$key};
$pethMainPseOperStatus = $$cisco_pethMainPseEntry{$cisco_pethMainPseOperStatus_oid.$key};
$pethMainPseConsumptionPower = $$cisco_pethMainPseEntry{$cisco_pethMainPseConsumptionPower_oid.$key};
if (defined($pethMainPsePower) && defined($pethMainPseOperStatus) && defined($pethMainPseConsumptionPower)){
if (!looks_like_number($pethMainPsePower) && !looks_like_number($pethMainPseOperStatus) && !looks_like_number($pethMainPseConsumptionPower)) {
$output = "Module:".$module." Device does not have PoE";
}else{
if ($pethMainPseOperStatus != 1){
$final_status = 2;
$output = "Module:".$module." Power Sourcing Equipment (PSE) is not on";
}else{
if($pethMainPsePower - $pethMainPseConsumptionPower < $o_warning){
$final_status = &set_status(1,$final_status);
}
if($pethMainPsePower - $pethMainPseConsumptionPower < $o_critical){
$final_status = &set_status(2,$final_status);
}
if ($output eq ""){
$output = "Module:".$module." Available:".$pethMainPsePower." W, Used:".$pethMainPseConsumptionPower." W, Remaining:".($pethMainPsePower - $pethMainPseConsumptionPower)." W";
$output_pd = " | M".$module."_Used=".$pethMainPseConsumptionPower.";".($pethMainPsePower - $o_warning).";".($pethMainPsePower - $o_critical).";0;".$pethMainPsePower;
}else{
$output.= " - Module:".$module." Available:".$pethMainPsePower." W, Used:".$pethMainPseConsumptionPower." W, Remaining:".($pethMainPsePower - $pethMainPseConsumptionPower)." W";
$output_pd.= " M".$module."_Used=".$pethMainPseConsumptionPower.";".($pethMainPsePower - $o_warning).";".($pethMainPsePower - $o_critical).";0;".$pethMainPsePower;
}
}
}
}
}
}
}else{
$output = "Device does not have PoE";
}
if ($final_status == 3) {
print $output," : UNKNOWN\n";
exit $ERRORS{"UNKNOWN"};
}
if ($final_status == 2) {
print $output," : CRITICAL",$output_pd,"\n";
exit $ERRORS{"CRITICAL"};
}
if ($final_status == 1) {
print $output," : WARNING",$output_pd,"\n";
exit $ERRORS{"WARNING"};
}
print $output," : OK",$output_pd,"\n";
exit $ERRORS{"OK"};
# ============================================================================
# ============================== NO CHECK DEFINED ============================
# ============================================================================
print "Unknown check type : UNKNOWN\n";
exit $ERRORS{"UNKNOWN"};