#! /usr/bin/perl -w

# Ce script génère une alarme quand la bande passante sur un lien
# est insuffisante. La bande passante est récupérée dans
# la base RTG.
# Les problèmes avec la base RTG génèrent un UNKNOWN.
# NB : les notifications UNKNOWN sont filtrées dans la configuration
# Nagios, pour éviter de réveiller l'astreinte si RTG ne marche pas.

use strict;
use Getopt::Std;
use DBI;
# use Data::Dumper;

my %options;
my $debug = 0;
# Au bout de quel intervalle la valeur d'un compteur est trop vieille
# (en secondes, ici 15 minutes)
my $max_interval = 15 * 60;

sub usage {
    my $arg = shift;    
    print <<EOF;

$arg

Usage:
 -H host : hôte cible
 -d description : description de l'interface
 -t direction : direction (in ou out)
 -w low,high : limites pour alarme warning (bande passante en Mbps)
 -c low,high : limites pour alarme critical (bande passante en Mbps)

EOF
   exit(3);
}

getopt("H:C:d:t:w:c:", \%options);
my $host = $options{H} || usage("pas d'hôte");

my $description = $options{d} || usage("pas de description");
my $direction = $options{t} || usage("pas de direction");
my $warning_levels = $options{w} || usage("pas de fourchette warning");
my $critical_levels = $options{c} || usage("pas de fourchette critical");

my ($warning_low_bandwidth, $warning_high_bandwidth) = split(/,/, $warning_levels);
my ($critical_low_bandwidth, $critical_high_bandwidth) = split(/,/, $critical_levels);

if (! ( defined($warning_low_bandwidth) &&
        defined($warning_high_bandwidth) &&
        defined($critical_low_bandwidth) &&
        defined($critical_high_bandwidth) )) {

    usage("fourchette warning/critical non définie");
}

if (! ( $warning_low_bandwidth =~ /\d+/ &&
        $warning_high_bandwidth =~ /\d+/ &&
        $critical_low_bandwidth =~ /\d+/ &&
        $critical_high_bandwidth =~ /\d+/ ) ) {
    usage("fourchette warning/critical : valeur non numérique");
}

if ( $warning_low_bandwidth > $warning_high_bandwidth ) {
    usage("valeur warning basse supérieure à valeur haute");
}

if ( $critical_low_bandwidth > $critical_high_bandwidth ) {
    usage("valeur critical basse supérieure à valeur haute");
}

if ( $warning_low_bandwidth < $critical_low_bandwidth ) {
    usage("valeur warning basse inférieure à valeur critical basse");
}

if ( $warning_high_bandwidth > $critical_high_bandwidth ) {
    usage("valeur warning haute supérieure à valeur critical haute");
}
my $rtg_table;
if ( $direction eq "in" ) {
    $rtg_table = "ifInOctets";
}
elsif ( $direction eq "out" ) {
    $rtg_table = "ifOutOctets";
}
else {
    usage("La direction est in ou out ($direction) !\n");
}

my $db = "rtg";
my $dbuser = "snmp";
my $dbhost = "acct.fr.clara.net";
my $password = "clar-2n";

my $dbh = DBI->connect("dbi:mysql:dbname=$db;host=$dbhost;password=$password", "$dbuser");

if (! $dbh) {
    print "UNKNOWN : connexion impossible base RTG : $DBI::errstr";
    exit(3); # UNKNOWN
}

my $interface_sql = "
    SELECT interface.name, interface.id, interface.description, router.rid
    FROM router, interface
    WHERE router.rid = interface.rid AND router.name = '$host'
    AND interface.description like '%${description}%' 
    AND interface.status ='active' 
";

print "$interface_sql\n" if $debug;

my $interfaces = $dbh->selectall_arrayref($interface_sql);

if (! $interfaces) {
    print "UNKNOWN : impossible de récupérer les interfaces dans RTG : $DBI::errstr";
    exit(3); # UNKNOWN
}

# Ce flag sera à 1 dès qu'on aura trouvé une interface avec la bonne description
my $interface_match;
my $interface_id;
my $router_id;

for my $interface (@{$interfaces}) {

    my $_name = $interface->[0];
    my $_interface_id = $interface->[1];
    my $_description = $interface->[2];
    my $_router_id = $interface->[3];

    print "Looking at interface $_name (id $_interface_id, $_description)\n" if $debug;
    # Cisco crée une interface pour le trafic MPLS, pas intéressé ici
    next if $_name =~ /mpls/i;

    # Une seule interface doit correspondre à la description
    if ($interface_match) {
        print "UNKNOWN : plusieurs interfaces avec description $description\n";
        exit(3); # UNKNOWN
    } else {
        $interface_match = 1;
        $interface_id = $_interface_id;
        $router_id = $_router_id;
    }

}

if (! $interface_match) {
    print "UNKNOWN : pas d'interface correspondant à la description $description\n";
    exit(3); # UNKNOWN
}

$rtg_table .= "_$router_id";

# Il faut vérifier avec Perl, sinon le SQL est trop lent...
# AND UNIX_TIMESTAMP() - UNIX_TIMESTAMP(dtime) < $max_interval

my $counters_sql = "
    SELECT UNIX_TIMESTAMP(dtime), counter FROM $rtg_table
    WHERE id = $interface_id
    ORDER BY dtime DESC LIMIT 2
";


print "$counters_sql\n" if $debug;

my $counters = $dbh->selectall_arrayref($counters_sql);

if (! $counters) {
    print "UNKNOWN : impossible de récupérer les compteurs dans RTG : $DBI::errstr";
    exit(3); # UNKNOWN
}

if ( ! (@{$counters} == 2) ) {
    print "UNKNOWN : impossible de récupérer les deux dernières " .
            "valeurs de compteur dans RTG\n";
    exit(3); # UNKNOWN
}

my $last_counter = $counters->[0]->[1];
my $previous_counter = $counters->[1]->[1];

my $last_date = $counters->[0]->[0];
my $previous_date = $counters->[1]->[0];
 
my $now = time;
my $elapsed_seconds = $last_date - $previous_date;

# Bande passante en Mbps
my $bandwidth = ( 8 * $last_counter ) / $elapsed_seconds;
$bandwidth = $bandwidth/1_000_000;
   
if ($debug) {
    print "now " . (scalar localtime $now) . "\n";
    print "last_date " . (scalar localtime $last_date) . "\n";
    print "previous_date " . (scalar localtime $previous_date) . "\n";
    print "elapsed_seconds $elapsed_seconds\n";
    print "last $last_counter previous $previous_counter\n";
    print "bandwidth $bandwidth\n";
}

if ( (($now - $last_date) > $max_interval)
            || (($now - $last_date) > $max_interval) ) {
    print "UNKNOWN : too old data in RTG: ", scalar localtime $previous_date, "\n";
    exit(3); # UNKNOWN
}

$bandwidth = int($bandwidth);

if ( $bandwidth < $critical_low_bandwidth ) {
    print "CRITICAL: $bandwidth Mbps (below $critical_low_bandwidth Mbps)\n";
    exit(2); # CRITICAL
}
elsif ( $bandwidth > $critical_high_bandwidth ) {
    print "CRITICAL: $bandwidth Mbps (over $critical_high_bandwidth Mbps)\n";
    exit(2); # CRITICAL
}
elsif ( $bandwidth < $warning_low_bandwidth ) {
    print "WARNING: $bandwidth Mbps (below $warning_low_bandwidth Mbps)\n";
    exit(1); # WARNING
}
elsif ( $bandwidth > $warning_high_bandwidth ) {
    print "WARNING: $bandwidth Mbps (over $warning_high_bandwidth Mbps)\n";
    exit(1); # WARNING
}
else {
    print "OK: $bandwidth Mbps (between $warning_low_bandwidth and $warning_high_bandwidth Mbps)\n";
    exit(0); # OK
}

