#!/usr/bin/perl -w
# nagios: +epn
# # =========================== PROGRAM LICENSE =================================
# # Copyright (c) 2008 - 2009
# # The Trustees of Columbia University in the City of New York
# # Academic Information Systems
# Change log
# # 1.3 - 2051214 - Guilherme
# # Add default port to SNMP;
# # Set default SNMP community to public;
# # Change usage description;
# ##===============================================================================
=head1 DESCRIPTION
 This module is written to deal with issues where snmp represent the data as integer while the data should be in floating point.
 We added -f function parameter which takes only two possible values addition and multiplication.  Any subtraction can be written
 as addition and any division can be written as multiplication

=cut

BEGIN {
    use File::Basename;
    use Net::SNMP;
    use Getopt::Std;
    use Nagios::Plugin;
    use Data::Dumper;
    use POSIX qw(ceil floor pow);

} # END BEGIN

my( $usagemsg ) = <<USAGE;
Usage: %s -H <hostname> [-C <community_string-Default public>] [-p <SNMP port-Default 161>] [-P <protocol 1|2c|3-Default 2c>] [-o <oid>] [-u <unit_string>] [-f <Math_operation sub|sum|mul|div>] [-a <Math operation value>] [-S <Service_name_string>] [-w <warning>] [-c <critical>]
USAGE
my( $blurb ) = <<BLURB;
This particular plugin has been created to deal with snmp data presentation with desired format.
BLURB

Nagios::Plugin->new(
    usage => "Usage: %s [ -v|--verbose ]  [-H <host>] "
    . "[ -C|--community_string=<community_string> ]",
);
my( $plugin ) = Nagios::Plugin->new(
    shortname   => ' ',
    usage       => $usagemsg,
    version     => '1.3',
    blurb       => $blurb,
    plugin  => basename $0,
    timeout     => 20,
);
=head2 Plugin Metadata

Metadata is documented in L<Nagios::Plugin> and L<Nagios::Plugin::Getopt>.

=cut
$plugin->add_arg(
    spec       => 'hostname|H=s',
    help       => [
    "Hostname to query",
    "IP address to query",
    ],
    label      => [ 'HOSTNAME', 'IP' ],
    required   => 1,
);

$plugin->add_arg(
    spec       => 'community_string|C=s',
    help       => ["community string for snmp_querry",],
    label      => [ 'COMMUNITY' ],
    default    => 'public',
    required   => 1,
);
$plugin->add_arg(
    spec       => 'port|p=s',
    help       => ["port number for snmp_querry",],
    label      => [ 'port'],
    default    => '161',
    required   => 0,
);
$plugin->add_arg(
    spec       => 'protocol|P=s',
    help       => ["snmp protocol",],
    label      => [ 'protocol'],
    default    => '2c',
    required   => 0,
);
$plugin->add_arg(
    spec       => 'oid|o=s',
    help       => ["oid string",],
    label      => [ 'oid'],
    required   => 1,
);
$plugin->add_arg(
  spec => 'unit|u=s',
  help =>
  qq{-u, --unit=String },
  required => 0,
);
$plugin->add_arg(
    spec       => 'function|f=s',
    help       => [
    "function string",
    ],
    label      => [ 'sum', 'sub', 'mul', 'div'],
    required   => 0,
);
$plugin->add_arg(
    spec       => 'argument|a=s',
    help       => [ "function string"],
    label      => [ 'argument'],
    required   => 0,
);
$plugin->add_arg(
  spec => 'service_name|S=s',
  help =>
  qq{-S, --service_name=String
   Service Name configurate in OpMon},
  required => 0,
  default => 'value'
);
$plugin->add_arg(
    spec => 'warning|w=s',
    help => [
    'Exit with WARNING status if less than BYTES bytes of disk are free',
    'Exit with WARNING status if less than PERCENT of disk is free',
    ],
    label => [ 'BYTES', 'PERCENT%' ],
    required => 0,
);
$plugin->add_arg(
    spec => 'critical|c=s',
    help => [
    'Exit with CRITICAL status if less than BYTES bytes of disk are free',
    'Exit with CRITICAL status if less than PERCENT of disk is free',
    ],
    label => [ 'BYTES', 'PERCENT%' ],
    required => 0,
);
$plugin->getopts;
my ( $opts ) =$plugin->opts;
my ( $ipaddress, $community, $port, $protocol, $oid, $unit, $function, $argument, $warning, $critical );

$ipaddress=$opts->get('hostname');
$community=$opts->get('community_string');
$port=$opts->get('port');
$protocol=$opts->get('protocol');
$oid=$opts->get('oid');
$unit=$opts->get('unit');
$function=$opts->get('function');
$argument=$opts->get('argument');
$warning=$opts->get('warning');
$critical=$opts->get('critical');

chomp $protocol;

my $snmp_timeout=20;
my $status = 0;
my $snmpdata="";
my $returnstring = "";
my $perfdata = "";

# Create the SNMP session
my ($s, $e) = Net::SNMP->session(
    -hostname   =>  $ipaddress,
    -port       =>  $port,
    -community  =>  $community,
    -version    => $protocol,
    -timeout    =>  $snmp_timeout,
);

main();

# Close the session
$s->close();

if($status >= 3){
  #($output,$exit_code);

  $plugin->nagios_exit(UNKNOWN,$returnstring);
}

#verifica thresholds
my $code = $plugin->check_threshold( check => $returnstring);
#adiciona perf data

#print Dumper $np;
my $perfInicio = "";
my $perfFim = "";

$returnstring = rndPlaces($returnstring, 2);

my $msg = $plugin->opts->service_name." = ".$returnstring;
if($plugin->opts->unit){
    $msg = $msg.$plugin->opts->unit;
    $returnstring = $returnstring.$plugin->opts->unit;
    if($plugin->opts->unit eq '%'){
        $perfInicio = "0";
        $perfFim = "100";
    }
}

my $w = "";
my $c = "";
if( $plugin->opts->warning ){
    unless ( $plugin->opts->warning =~ /:/){
    $w = $plugin->opts->warning;
    }
}
if( $plugin->opts->critical ){
    unless ( $plugin->opts->critical =~ /:/){
        $c = $plugin->opts->critical;
    }
}


my $perf = " | '".$plugin->opts->service_name."'=".$returnstring.";".$w.";".$c.";".$perfInicio.";".$perfFim;

$plugin->nagios_exit($code,$msg.$perf);


####################################################################
# This is where we gather data via SNMP and return results         #
####################################################################

sub main {

    #######################################################

    if (!defined($s->get_request($oid))) {
        $returnstring = "SNMP agent not responding";
        $status = 3;
        return 1;
    }


    foreach ($s->var_bind_names()) {
        $snmpdata = $s->var_bind_list()->{$_};
        #print Dumper $snmpdata;

        unless ($snmpdata =~ /^[+-]?((\d+(\.\d*)?)|(\.\d+))$/) {
            $plugin->nagios_exit(3,"Return value isnt a number.");
        }

        my $return_value;
        if($function){ #se o argumeto for uma OID deve buscar o valor da OID para calcular
            my $arg_oid;
            if( $argument =~ /^\.[0-9]/ ){
                #print Dumper $s->get_request($argument);
                $arg_oid = $argument;
                if (!defined($s->get_request($argument))) {
                    $returnstring = "SNMP agent not responding";
                    $status = 3;
                    return 1;
                }

                foreach ($s->var_bind_names()) {
                    $argument = $s->var_bind_list()->{$_};
                }
                #print Dumper $argument;
            }
            unless ( $argument =~ /^\d+?$/ ) {
                $plugin->nagios_exit(3,"Could not get SNMP data from OID: $arg_oid");
            }
            $return_value = perform_calculation($snmpdata, $function, $argument);

        }else{
            $return_value = $snmpdata;
        }


        $returnstring=$return_value;
        $status=0;
    }

}

sub perform_calculation {
    my ($data, $action, $arg) =@_;
    #print Dumper $data;
    #print Dumper $action;
    #print Dumper $arg;

    my $return_data;

    if ($action eq 'mul') {
        $return_data=($data) * ($arg)
    }
    elsif ( $action eq 'sum' ) {
        $return_data= ( ( $data ) + ( $arg ) );
    }
        elsif ( $action eq 'div' ) {
        $return_data= ( ( $data ) / ( $arg ) );
    }
        elsif ( $action eq 'sub' ) {
        $return_data= ( ( $data ) - ( $arg ) );
    }
	elsif ( $action eq 'percentage' ) {
        $return_data= ( ( $data ) / ( $arg ) * 100 );
    }
    else {
        print "only mul,add,div and sub are valid functions"
    }
}

sub rndZero
{
    my($val) = shift;
    my $rounded = $val < 0 ?
       POSIX::ceil($val - 0.5) : POSIX::floor($val + 0.5);
    return $rounded;
}

sub rndPlaces
{
    my($val, $places) = @_;
    my $rounded = rndZero($val * POSIX::pow(10.0, $places)) /
       POSIX::pow(10.0, $places);
    return $rounded;
}
