
# nagios: -epn
############################## check_snmp_adva #########
# Date: 2015-10-30
# Interface Checks für ADVA Geräte 
# - Adva ONLY
# Author  : Katharina Drexel <katharina.drexel@noris.de>
#################################################################
#
# Help : ./check_snmp_adva -h

use strict;
use warnings;
use Net::SNMP;
use Getopt::Long;
use Switch;
use Data::Dumper;

# Nagios specific

use lib "/usr/lib/nagios/plugins";
use utils qw(%ERRORS $TIMEOUT);
my $TIMEOUT = 15;

my @Nagios_state = ("UNKNOWN","OK","WARNING","CRITICAL"); # Nagios states coding

# SNMP Datas
# ADVA 
my $AdvaInterfaceMIB = '.1.3.6.1.2.1.2.2.1.'; # base table
my %advaTables = (
    IfDescr => $AdvaInterfaceMIB . '2',	  # Adva Interface Description table
    ifAdminStatus => $AdvaInterfaceMIB . '7',  # Adva Interface Administrative Status table
    ifOperStatus => $AdvaInterfaceMIB . '8', # Adva Operating Status table
);

# Globals

my $Version='6.6';

my $o_host = 	undef; 		# hostname
my $o_community = undef; 	# community
my $o_port = 	161; 		# port
my $o_help=	undef; 		# wan't some help ?
my $o_verb=	undef;		# verbose mode
my $o_version=	undef;		# print version
my $o_timeout=  undef; 		# Timeout (Default 5)
my $o_version2= undef;          # use snmp v2c
my $o_domain= 	undef;          # use IPv6

# SNMPv3 specific
my $o_login=	undef;		# Login for snmpv3
my $o_passwd=	undef;		# Pass for snmpv3
my $v3protocols=undef;	# V3 protocol list.
my $o_authproto='md5';		# Auth protocol
my $o_privproto='des';		# Priv protocol
my $o_privpass= undef;		# priv password

# Adva specific
my $o_env         = undef;
my $o_allports    = undef;
my $o_allalarms   = undef;
my $o_noportcheck = undef;
my $o_check_ports =	undef;

# functions

sub p_version { print "check_snmp_env version : $Version\n"; }

sub print_usage {
    print "Usage: $0 [-v] [-6] -H <host> -C <snmp_community> [-2] | (-l login -x passwd [-X pass -L <authp>,<privp>])  [-p <port>] [-t <timeout>] [-V] [-all] [--env] [--port <port> [--port <port2> ...]] [--allports] [--noportcheck]\n";
}

sub isnnum { # Return true if arg is not a number
  my $num = shift;
  if ( $num =~ /^(\d+\.?\d*)|(^\.\d+)$/ ) { return 0 ;}
  return 1;
}

sub help {
   print "\nSNMP environmental Monitor for Nagios version ",$Version,"\n";
   print "GPL Licence, (c)2006-2007 Patrick Proy\n";
   print "GPL Licence, (c)2015 Klaus.Franken\@noris.de\n\n";
   print_usage();
   print <<EOT;

Options:
-v, --verbose
   print extra debugging information 
-h, --help
   print this help message
-6, --use-ipv6
   Use IPv6 connection
-H, --hostname=HOST
   name or IP address of host to check
-C, --community=COMMUNITY NAME
   community name for the host's SNMP agent (implies v1 protocol)
-2, --v2c
   Use snmp v2c
-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 md5)
   <privproto> : Priv protocole (des|aes : default des) 
-P, --snmpport=PORT
   SNMP port (Default 161)
-t, --timeout=INTEGER
   timeout for SNMP in seconds (Default: 5)
-V, --version
   prints version number
-e, --env
    check Environent alarams (fan, power (everything not beeing a port))
-a, --allports
    check all ports
-p, --port
    check only given port(s)
-A, --all
    check env and all ports (default)
-n, --noportcheck
    do not check that given ports exists (enabled by default)
EOT
}

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,   		'snmpport: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,
	    '2'             => \$o_version2,    'v2c'           => \$o_version2,
        'e'             => \$o_env,         'env'           => \$o_env,
        'a'             => \$o_allports,    'allports'      => \$o_allports,
        'p:s@'          => \$o_check_ports, 'port:s@'       => \$o_check_ports,
        'n'             => \$o_noportcheck, 'noportcheck'   => \$o_noportcheck,
	);

    # 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"}};
    if ( ! defined($o_host) ) {
        # check host and filter
        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,2c,3 protocols!\n"; print_usage(); 
        exit $ERRORS{"UNKNOWN"}
    }
	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];	}	# Auth protocol
	    if (defined ($v3proto[1])) {$o_privproto=$v3proto[1];	}	# Priv  protocol
	    if ((defined ($v3proto[1])) && (!defined($o_privpass))) {
	        print "Put snmp V3 priv login info with priv protocols!\n"; 
            print_usage(); 
            exit $ERRORS{"UNKNOWN"}
        }
	}

    if (not defined($o_env) and not defined($o_allports) and not defined($o_check_ports)) {
        $o_allalarms=1;
    }
}

sub getrequest {
  my $host = shift;
  my $version = shift;
  my $timeout = shift;
  my $community = shift;
  my $oid = shift;
  my $result;
  my ($session, $error) = Net::SNMP->session(
            -hostname     => $host,
            -version      => $version,
            -timeout      => $timeout,
            -community    => $community,
        );
                my $status = $session -> get_request($oid);
                if ( !defined($status) ) {
                  print "No admin status found: $!\n";
                  exit $ERRORS{"UNKNOWN"}; 
                }

                for my $id (keys(%$status)) {
                  $result = $$status{$id};
                }
                return $result; 
}

# For verbose output
sub verb { my $t=shift; print $t,"\n" if defined($o_verb) ; }

##############################################################################
#### MAIN #####
check_options();
$o_version2 = "v2c" if ( !defined $o_version2);

unless ( $o_noportcheck ) {
my ( $cstate, $wstate, $ustate, $nstate ) = ( 0, 0, 0, 0 );
my $session;
my $error;
my %ifoperstatus;

my $portdescr;
my $admstatus;

my %admin;
$admin{'up'} = 1;
$admin{'down'} = 2;
$admin{'testing'} = 3;

my %operating;
$operating{'up'} = 1;             # OK
$operating{'down'} = 2;           # CRIT
$operating{'testing'} = 3;        # WARN
$operating{'unknown'} = 4;        # UNKNOWN
$operating{'dormant'} = 5;        # WARN
$operating{'notPresent'} = 6;     # CRIT
$operating{'lowerLayerDown'} = 7; # CRIT


($session, $error) = Net::SNMP->session(
            -hostname     => $o_host,
            -version      => $o_version2,
            -timeout      => $o_timeout,
            -community    => $o_community, 
        );

my $advaPortAdm  = $advaTables{ifAdminStatus};
my $advaPortOpr  = $advaTables{ifOperStatus};
my $advaPortDesc = $advaTables{IfDescr};
$portdescr =
                ( Net::SNMP->VERSION lt 4 )
                ? $session->get_table($advaPortDesc )
                : $session->get_table( Baseoid => $advaPortDesc);


my $suffix;
my @descrid;
for my $id (keys(%$portdescr)) {
            my $portname = $$portdescr{$id};
            if ($portname =~ /^[C|N]/) {
                verb("   GEFUNDEN: $portname: $id");
                @descrid = split(/\./, $id);
                $suffix = $descrid[-1];
                my $admstatusoid = $advaPortAdm.'.'.$suffix;  
                my $oprstatusoid = $advaPortOpr.'.'.$suffix;
                my $admstatus = getrequest($o_host,$o_version2,$o_timeout,$o_community,$admstatusoid);
                if ( $admstatus == $admin{'up'} ) {
                  my $oprstatus = getrequest($o_host,$o_version2,$o_timeout,$o_community,$oprstatusoid);
                  if ( $oprstatus != $operating{'up'} ) {
                    $ifoperstatus{$portname} = $oprstatus;
                  }
                }
            }
}
$session->close;
foreach my $port (keys %ifoperstatus) {
  $nstate = 0;
  if ( $ifoperstatus{$port} == $operating{'down'} or 
      $ifoperstatus{$port} == $operating{'notPresent'} or   
      $ifoperstatus{$port} == $operating{'lowerLayerDown'} ) {
        $cstate = 1;
  } elsif ( $ifoperstatus{$port} == $operating{'unknown'} ) {
      $ustate = 1;
  } elsif ( $ifoperstatus{$port} == $operating{'testing'} or 
      $ifoperstatus{$port} == $operating{'dormant'} ) {
      $wstate = 1;
  } else {
      print "No operating status found for Port $port\n";
      $ustate = 1;
      $nstate = 1;
  }
      my $value = $ifoperstatus{$port};
      my %rhash = reverse %operating;
      my $statusval = $rhash{$value};
      print "$port has status $statusval\n" if $nstate == 0;
} 

if ( $cstate == 1 ) {
    exit $ERRORS{"CRITICAL"};
} elsif ( $ustate == 1 ) {
    exit $ERRORS{"UNKNOWN"};
} elsif ( $wstate == 1 ) {
    exit $ERRORS{"WARNING"};
} else {
    print "All ports have status 'up'\n";
    exit $ERRORS{"OK"};
}
} # END unless noportstate

if ( $o_env ) {
  my ( $cstate, $wstate, $ustate, $nstate ) = ( 0, 0, 0, 0 );
  my $pcounter = 0;
  my $psu1descoid = ".1.3.6.1.4.1.2544.2.5.5.1.1.1.100729088";
  my $psu2descoid = ".1.3.6.1.4.1.2544.2.5.5.1.1.1.100733696";
  my $psu1tempoid = ".1.3.6.1.4.1.2544.1.11.2.4.2.1.1.1.100729088";
  my $psu2tempoid = ".1.3.6.1.4.1.2544.1.11.2.4.2.1.1.1.100733696";
  my %psu;
  %psu = (
    $psu1descoid => $psu1tempoid,
    $psu2descoid => $psu2tempoid,
  ); 
  foreach my $psudescoid (keys %psu) {
    $pcounter++;
    my $psudesc =   getrequest($o_host,$o_version2,$o_timeout,$o_community,$psudescoid);
    my $psutemp10 = getrequest($o_host,$o_version2,$o_timeout,$o_community,$psu{$psudescoid});
    my $psutemp = $psutemp10/10 or (print "Konnte PSU Temp Wert fuer $psudesc nicht ermitteln: $!\n" and $ustate = 1);
    my $psuwarn = 75;
    my $psucrit = 80;
    if ( $psutemp > $psucrit ) {
        print "$psudesc-$pcounter too hot: $psutemp °C\n";
        $cstate = 1;
    } elsif ( $psutemp > $psuwarn ) {
        print "$psudesc-$pcounter too warm: $psutemp °C\n";
        $wstate = 1;
    } else {
        print "$psudesc-$pcounter OK: $psutemp °C\n";
    }
  }

  if ( $cstate == 1 ) {
      exit $ERRORS{"CRITICAL"};
  } elsif ( $ustate == 1 ) {
      exit $ERRORS{"UNKNOWN"};
  } elsif ( $wstate == 1 ) {
      exit $ERRORS{"WARNING"};
  } else {
      exit $ERRORS{"OK"};
  } 
} # END $o_env (-e)

# PowerConsumption: .1.3.6.1.4.1.2544.1.11.2.4.2.12.1.1.33619968
# MaxPC:            .1.3.6.1.4.1.2544.1.11.2.4.2.12.1.3.117506048 

#snmpwalk -v2c -cpublic ncu1-east-nbg6.adva.noris.de  .1.3.6.1.4.1.2544.2.5.5.1.1.1
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.33619968 = STRING: "SH9HU"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.67174400 = STRING: "CEM/9HU"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.100729088 = STRING: "PSU/9HU-AC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.100729600 = STRING: "EDFA-C-D20-VLGC-DM"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.100729856 = STRING: "10TCE-PCN-16GU+AES100G"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.100730368 = STRING: "10TCE-PCN-16GU+AES100G"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.100730880 = STRING: "5TCE-PCN-10GU+AES10G"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.100731136 = STRING: "5TCE-PCN-10GU+AES10G"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.100733696 = STRING: "PSU/9HU-AC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.100737280 = STRING: "NCU-II"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.100737536 = STRING: "SCU-II"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.117506048 = STRING: "40CSM/2HU-#19590-#19200"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151061505 = STRING: "SFP+CDR/10GU/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151061506 = STRING: "SFP+CDR/10GU/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151061507 = STRING: "SFP+CDR/10GU/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151061508 = STRING: "SFP+CDR/10GU/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151061509 = STRING: "SFP+CDR/10GU/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151061510 = STRING: "SFP+CDR/10GU/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151061511 = STRING: "SFP+CDR/10GU/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151061512 = STRING: "SFP+CDR/10GU/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151061513 = STRING: "SFP+/16GFC/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151061569 = STRING: "CFP/4x28G/#19595-#19520L/SM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151062020 = STRING: "SFP+/16GFC/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151062021 = STRING: "SFP+/16GFC/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151062022 = STRING: "SFP+/16GFC/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151062023 = STRING: "SFP+/16GFC/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151062024 = STRING: "SFP+/16GFC/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151062025 = STRING: "SFP+/16GFC/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151062026 = STRING: "SFP+/16GFC/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151062081 = STRING: "CFP/4x28G/#19355-#19280L/SM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151062529 = STRING: "SFP+/11GU/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151062593 = STRING: "SFP+/11GU/DCTV/SM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151062785 = STRING: "SFP+/11GU/850I/MM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.151062849 = STRING: "SFP+/11GU/DCTV/SM/LC"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.184614913 = STRING: "FAN/9HU"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.184614914 = STRING: "FAN/9HU"
#iso.3.6.1.4.1.2544.2.5.5.1.1.1.184614915 = STRING: "FAN/9HU"


