#!/usr/bin/perl
#
# check_cisco-errors.pl  -  Check port error counters
#
# v0.3a 2011 - Christopher Noyes  email:christopher.noyes@pw.utc.com
#
#  Based on check_dot3.pl by Peter Wirdemo
#

use strict;
use warnings;
use vars qw($PROGNAME $VERSION $QSTRING);
use File::Basename qw(basename);
use Nagios::Plugin;
use Net::SNMP;
use Net::SNMP::Interfaces;
use Net::SNMP::Interfaces::Details;
use DBI;
use Data::Dumper;

$PROGNAME = basename($0);
$VERSION = '0.3a';
$QSTRING = 'christopher.noyes@pw.utc.com';

my $savedir = "/etc/tmp/check_cisco_errors";
my $performance = 0;

my $np = Nagios::Plugin->new(
    usage => "Usage: %s -H <hostname> -C <community> -i <switchport> ...\n",
    version => $VERSION,
    plugin => $PROGNAME,
    shortname => "check_cisco_errors",
    blurb => "Get port error counters from the host.\n"
       . "Add all values from the interface and calculate the sum of all errors.\n"
       . "If the sum/second (i.e. since last run) is larger than warning or critical\n"
       . "appropiate exit values are returned to Nagios.",
    extra => "\n\nWritten 2011 Christopher Noyes christopher.noyes\@pw.utc.com",
    timeout => 30,
    );

$np->add_arg(
    spec => 'hostname|H=s',
    help => "-H, --hostname=<hostname>",
    required => 1,
    );

$np->add_arg(
    spec => 'community|C=s',
    help => "-C, --community=<snmp read-only community string>",
    required => 1,
    );

$np->add_arg(
    spec => 'switchport|i=s',
    help => "-i, --switchport=<full cisco name of the interface to be checked (i.e. FastEthernet0/1)>",
    required => 1,
    );

$np->add_arg(
    spec => 'warning|w=s',
    help => "-w, --warning=<warn threshold for errors/second>",
    required => 0,
    );

$np->add_arg(
    spec => 'critical|c=s',
    help => "-c, --critical=<critical threshold for errors/second>",
    required => 0,
    );


$np->getopts;

# Assign, then check arguments

my $verbose = $np->opts->verbose;

my $hostname = $np->opts->hostname;
print "hostname=$hostname\n" if ( $verbose );

my $community = $np->opts->community if ( $np->opts->community );
print "community=$community\n" if ( $verbose );

my $switchport = $np->opts->switchport if ( $np->opts->switchport );
print "switchport=$switchport\n" if ( $verbose );

my $warning = $np->opts->warning if ( $np->opts->warning );

my $critical = $np->opts->critical if ( $np->opts->critical );


$np->nagios_exit(UNKNOWN, 'Hostname contains invalid characters.')
    if ($hostname =~ /\`|\~|\!|\$|\%|\^|\&|\*|\||\'|\"|\<|\>|\?|\,|\(|\)|\=/);

if ( ! -d $savedir ) {
    print "Creating directory :$savedir\n";
    mkdir($savedir);
    my($mode);
    $mode = 0755;
    chmod $mode, $savedir;
}
#if ( ! -d $savedir ) {
#    chdir($savedir);
#    $np->nagios_exit(UNKNOWN, $!);
#}

$SIG{ALRM} = sub {
    $np->nagios_exit(UNKNOWN, 'plugin timed out.');
};
alarm $np->opts->timeout;

my $interfaces = Net::SNMP::Interfaces->new(Hostname => $hostname, Community => $community);
my $inter = $interfaces->interface($switchport);


my $ifind = $inter->index();
my $inerr = $inter->ifInErrors();
my $outerr = $inter->ifOutErrors();
my $toterr = $inerr + $outerr;


##########################################
#
# Now, do some filesystem stuff....
#
##########################################

my $db = $savedir . "/" . $hostname . "_ifIndex." . $ifind . ".db";
my $prev_cnt = 0;
my $prev_time = 0;
if ( open(IN,"<$db") ) {
    print "Reading database $db\n" if ( $verbose );
    ($prev_time,$prev_cnt) = split(/:/,<IN>);
    print "read prev_time=$prev_time (" . localtime($prev_time) .") \n" if ( $verbose );
    print "read prev_cnt=$prev_cnt\n" if ( $verbose );
    close(IN);
} else {
    print "Read check skipped.\n\n";
}



my $curr_cnt = $toterr;
my $curr_time = time;


if ( open(OUT,">$db") ) {
    print "Writing database $db\n" if ( $verbose );
    print OUT $curr_time . ":" . $curr_cnt;
    print "wrote curr_time=$curr_time (" . localtime($curr_time) . ") \n" if ( $verbose );
    print "wrote curr_cnt=$curr_cnt\n" if ( $verbose );
    close(OUT);
} else {
    die "Cannot create file: $!\n\n";
}

#alarm(0);


#################################################
#
#
#  Check the old and current values and times to get error packets per second
#
#
#################################################



my $errors = 0;
my $persec = 0;
my $diff_cnt = 0;
my $diff_time = 0;
my $diff_min_sec = 0;
my $data_avail;
my $minutes = 0;

if ( $prev_time ) {
    $diff_time = $curr_time - $prev_time;
    $minutes = int($diff_time/60);
    $diff_min_sec = sprintf("%dm%ds",$minutes,$diff_time - $minutes*60);
    $diff_cnt = $curr_cnt - $prev_cnt;
    if ( $diff_cnt < 0 ) {
        $diff_cnt = $curr_cnt;
    }
    if ( $diff_time > 0 ) {
        $persec = int($diff_cnt/$diff_time);
        $data_avail ++;
    }
}

my $perfstr = "";
$perfstr = "AllErr=$curr_cnt AllPerSec=$persec $perfstr";
my $errorstr = ", Diff=$diff_cnt/$diff_min_sec ($persec/s) ";



unless ( $data_avail ) {
    $np->nagios_die( "Could not retrieve data!" );
}
if ( $persec > 0 ) {
    print "Current error level per seconds is $persec\n" if ( $verbose );
    if ( defined($warning) ) {
        print "warning level is at $warning\n" if ( $verbose );
        if ( $persec > $warning ) {
            $np->nagios_exit( WARNING, $errorstr );
        }
    }
    if ( defined($critical) ) {
        print "critical level is at $critical\n" if ( $verbose );
        if ( $persec > $critical ) {
            $np->nagios_exit( CRITICAL, $errorstr );
        }
    }

} else {

    $np->nagios_exit( OK ,$errorstr );
}