#! /usr/bin/perl -w
use strict;
use Carp;
use Net::SNMP;
use Getopt::Std;
use vars qw/$opt_h $opt_C $opt_t $opt_w $opt_c/;
# use Data::Dumper;

# Options
my ($host , $community, $npe_type, $warning_level, $critical_level);

sub usage {
   print <<EOF;

Usage:
$0 -h host -c community -w percentage -c percentage
 -h host : hôte cible
 -C community : communauté SNMP utilisée
 -t NPE-400|NPE-G1|sup-routing|sup-switching : type de Network Processing Engine
 -w percentage : pourcentage d'utilisation CPU qui déclenche une alarme "warning" (0 -> 100)
 -c percentage : pourcentage d'utilisation CPU qui déclenche une alarme "critical" warning (0 -> 100)

EOF
   exit(3);
}

getopt("h:C:t:w:c:");
$host = $opt_h || usage();
$community = $opt_C || usage();
$npe_type = $opt_t || usage();
$warning_level = $opt_w || usage();
$critical_level = $opt_c || usage();

$warning_level =~ /\d+/ || usage();
$critical_level =~ /\d+/ || usage();
$npe_type =~ /NPE-G1|NPE-400|sup-routing|sup-switching/ || usage();

$npe_type = "CPU of Routing Processor" if $npe_type eq "sup-routing";
$npe_type = "CPU of Switching Processor" if $npe_type eq "sup-switching";

if (! ( $warning_level > 0 && $warning_level < 100 ) ) {
    usage();
}

if (! ( $critical_level > 0 && $critical_level < 100 ) ) {
    usage();
}


# On veut récupérer le taux CPU de la NPE G1, on procède en trois coups :
#
# 1) On récupère l'index correspondant à la NPE dans la table
#    des entités physiques :
#       entPhysicalDescr.$entity_index = "NPE-G1"
# 2) On récupère l'index CPU :
#       cpmCPUTotalPhysicalIndex.$cpu_index = $entity_index
# 3) On récupère le taux CPU :
#       cpmCPUTotal5minRev.$cpu_index = $cpu_utilization

my $entity_descr_table_oid = ".1.3.6.1.2.1.47.1.1.1.1.2";
my $cpu_physical_index_table_oid = ".1.3.6.1.4.1.9.9.109.1.1.1.1.2";
my $cpu_5min_table_oid = ".1.3.6.1.4.1.9.9.109.1.1.1.1.8";

my ($session, $error) =
   Net::SNMP->session(-hostname => $host, -version => "2c", -community => $community);

if (not defined($session)) {
   print "Impossible d'ouvrir une session SNMP avec $host: $error !\n";
   exit(3); # UNKNOWN
}

# 1) On récupère l'index correspondant à la NPE G1 

my $entity_index = table_index_for_value(
    session => $session,
    table_oid => $entity_descr_table_oid,
    table_label => "entPhysicalDescr",
    value => $npe_type,
    pattern_matching => 1,
);
     
# 2) On récupère l'index CPU

my $cpu_index = table_index_for_value(
    session => $session,
    table_oid => $cpu_physical_index_table_oid,
    table_label => "cpmCPUTotalPhysicalIndex",
    value => $entity_index,
);

# 3) On récupère le taux CPU :

my $cpu_oid = "$cpu_5min_table_oid.$cpu_index";

my $result = $session->get_request(-varbindlist => [ $cpu_oid ]);

if (not defined($result)) {
    my $error = $session->error();
    print "Impossible de récupérer l'utilisation CPU sur $host : $error\n";
    exit(3); # UNKNOWN
}

my $cpu_utilization = $result->{$cpu_oid};

if ( $cpu_utilization > $critical_level ) {
    print "CRITICAL: $cpu_utilization% CPU\n";
    exit(2); # CRITICAL
}

elsif ( $cpu_utilization > $warning_level ) {
    print "WARNING: $cpu_utilization% CPU\n";
    exit(1); # WARNING
}

else {
    print "OK: $cpu_utilization% CPU\n";
    exit(0); # OK
}

sub table_index_for_value {
    # Retourne l'index correspondant à une valeur donnée dans une table.

    my %args = @_;
    my $session = $args{session} || croak "session not defined";
    my $table_oid = $args{table_oid} || croak "table_oid not defined";
    # label used for error messages
    my $table_label = $args{table_label} || croak "table_label not defined";
    my $value = $args{value} || croak "value not defined";
    my $pattern_matching = $args{pattern_matching} || 1;

    my $result = $session->get_table(-baseoid => $table_oid);

    if (not defined($result)) {
        my $error = $session->error();
        print "Impossible de récupérer la table $table_label : $error\n";
        exit(3); # UNKNOWN
    }

    my $result_index;
    # On trie les index pour utiliser le premier qui matche.
    my @indexes = sort { (reverse split /\./, $a)[0]
                               <=> (reverse split /\./, $b)[0]
                       } keys(%{$result});

    for my $index (@indexes) {
        if ($pattern_matching) {
            next unless $result->{$index} =~ /$value/;
        } else {
            next unless $result->{$index} eq $value;
        }
        $result_index = $index;
        last;
    }
    
    if (! defined($result_index) ) {
        print "Pas d'index dans $table_label pour valeur $value sur $host !\n";
        exit(3); # UNKNOWN
    }

    # Seul l'index est intéressant, pas tout l'OID.
    ($result_index) = reverse split /\./, $result_index;
    return $result_index;
}

__END__


# snmpwalk -Of -cpassword -v2c ig88 .1.3.6.1.2.1.47.1.1.1.1.2.2

 .iso.org.dod.internet.mgmt.mib-2.entityMIB.entityMIBObjects.entityPhysical.entPhysicalTable.entPhysicalEntry.entPhysicalDescr.2 = STRING: Cisco 7200 Series Network Processing Engine NPE-G1

# snmpwalk -Of -cpassword -v2c ig88 .1.3.6.1.4.1.9.9.109.1.1.1.1.2

 .iso.org.dod.internet.private.enterprises.cisco.ciscoMgmt.ciscoProcessMIB.ciscoProcessMIBObjects.cpmCPU.cpmCPUTotalTable.cpmCPUTotalEntry.cpmCPUTotalPhysicalIndex.1 = INTEGER: 2


# snmpwalk -Of -cpassword -v2c ig88 .1.3.6.1.4.1.9.9.109.1.1.1.1.8

 .iso.org.dod.internet.private.enterprises.cisco.ciscoMgmt.ciscoProcessMIB.ciscoProcessMIBObjects.cpmCPU.cpmCPUTotalTable.cpmCPUTotalEntry.cpmCPUTotal5minRev.1 = Gauge32: 38


