#!/usr/bin/perl -w
######################################
# Info : Check Cisco 2800 Series Performance (CPU and Memory)
# Version : 3.0
# Date : 12th February 2013
# Author  : Lukasz Ciesluk
# Help : lukaszciesluk@gmail.com
######################################
#
# Run :
# chmod +x check_CPUMemCisco2800.pl
# ./check_CPUMemCisco2800.pl -h (for help)
#

use strict;
use warnings;
use SNMP;
use Net::SNMP qw(snmp_dispatcher oid_lex_sort);
use Getopt::Long;
use Net::Ping;
use Time::HiRes qw(tv_interval gettimeofday);
use lib "/opt/nagios/libexec";

use vars qw(%ERRORS $default_timeout);
my $default_timeout = 15;
my %ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);

######### Cisco OIDs
my $cpu5min_oid = "1.3.6.1.4.1.9.9.109.1.1.1.1.8"; #The overall CPU busy percentage in the last 5 minute period
my $cpu1min_oid = "1.3.6.1.4.1.9.9.109.1.1.1.1.7"; #The overall CPU busy percentage in the last 1 minute period
my $cpu5sec_oid = "1.3.6.1.4.1.9.9.109.1.1.1.1.6"; #The overall CPU busy percentage in the last 5 second period
my %cpu5min_array = ("cpu5min",$cpu5min_oid);
my %cpu1min_array = ("cpu1min",$cpu1min_oid);
my %cpu5sec_array = ("cpu5sec",$cpu5sec_oid);

my $memory_cpu_used_oid = "1.3.6.1.4.1.9.9.48.1.1.1.5"; #.1 - for CPU, .2 - for I/O
my $memory_cpu_free_oid = "1.3.6.1.4.1.9.9.48.1.1.1.6"; #.1 - for CPU, .2 - for I/O
my %memory_cpu_used_array = ("memory_used_cpu",$memory_cpu_used_oid);
my %memory_cpu_free_array = ("memory_free_cpu",$memory_cpu_free_oid);

######### Additional info : http://knowledgebase.solarwinds.com/kb/questions/1195/__print

my $cisco_sysname = "1.3.6.1.2.1.1.5";
my %sysname_array = ("sysname",$cisco_sysname);

######### Globals
my $help = undef;
my $security_levelR1 = undef;									  # Security level e.g. authPriv
my $username = undef;                                             # SNMP Username e.g. test_user
my $auth_protocol = undef;                                        # Auth protocol e.g. SHA
my $auth_password = undef;                                        # Password for auth protocol
my $priv_protocol = undef;                                        # Priv protocol e.g. DES
my $priv_password = undef;                                        # Priv password for priv protocol
my $host = undef;                                                 # hostnames
my $snmp_version = undef;
my $community = undef;

my $result_cpu5min = undef;
my $result_cpu1min = undef;
my $result_cpu5sec = undef;
my $result_cpuio_used = undef;
my $result_cpuio_free = undef;

my $final_cpu5min = undef;
my $final_cpu1min = undef;
my $final_cpu5sec = undef;
my $final_cpuio_used = undef;
my $final_cpuio_free = undef;

my $licznik_cpuio_used = 0;
my $licznik_cpuio_free = 0;

my @hosts;
my $session;
my $error;
my $error_level = 0;
my $output_message = "";
my $output_message2 = "";
my $host_sysName;
my $cpu_free_performance = "";

my $performance_warning_cpu;
my $performance_critical_cpu;

my $performance_warning_mem;
my $performance_critical_mem;

my $host_snmptime;

sub usage {
    print "$0 <--snmpv2> <--community> --seclev <securityLevel> -u <user> -a <authProtocol> -A <authPassword> -x <privProtocl> -X <privPass> -H <host> -W <warning_level_for_cpu> -C <critical_level_for_cpu> -w <warning_level_for_memory> -c <critical_level_for_memory>\n";
}

sub getmaxerrorlevel($) {
        my $input = "@_";
		if ($error_level <= $input) {
			$error_level = $input;
		}
}

sub credentials_snmpv2 {
	my ($adres_hosta) = @_;
	my %credentials = (
		-hostname 		  => $adres_hosta,
		-version 		  => 'snmpv2c',
		-community		  => $community
	);

	return %credentials;
}

sub credentials_authnopriv {
	my ($adres_hosta) = @_;
	my %credentials = (
		-hostname 		  => $adres_hosta,
		-version 		  => 'snmpv3',
		-username         => $username,
		-authpassword     => $auth_password,
		-authprotocol     => $auth_protocol
	);

	return %credentials;
}

sub credentials_authpriv {
	my ($adres_hosta) = @_;
	my %credentials = (
		-hostname 		  => $adres_hosta,
		-version 		  => 'snmpv3',
		-username         => $username,
		-authpassword     => $auth_password,
		-authprotocol     => $auth_protocol,
		-privpassword     => $priv_password,
		-privprotocol     => $priv_protocol
	);
	
	return %credentials;
}

sub create_credentials {
	my ($adres) = @_;
	if ($snmp_version ne "snmpv3") {
		return credentials_snmpv2($adres);
	}
	if ($security_levelR1 eq "authNoPriv") {
		return credentials_authnopriv($adres);
	} elsif ($security_levelR1 eq "authPriv") {
		return credentials_authpriv($adres);
	}
}

sub help {
   print "\nCisco 2800 Series Performance (CPU and Memory)\n";
   usage();
   print <<EOT;
-h --help
   print this help message
--snmpv2
   using snmp v2 instead of snmp v3
--community COMMUNITY
   community for snmp v2
–l --seclev=SECLEV	
   security level for machine e.g. authPriv
-u --username=USERNAME
   username e.g. test_user
-a --authprotocol=PROTOCOL
   protocol for auth e.g. SHA
-A --authpassword=PASSWORD
   password for auth
-x --privprotocol=PROTOCOL
   protocol for auth e.g. DES
-X --privpassword=PASSWORD
   password for auth
-H --hostname=HOST(s)
   name or IP address of host(s)
-W --warningcpu=WARNING_LEVEL
   warning performance level for cpu
-C --criticalcpu=CRITICAL_LEVEL
   critical performnce level for cpu
-w --warningmem=WARNING_LEVEL
   warning performance level for memory
-c --criticalmem=CRITICAL_LEVEL
   critical performnce level for memory
EOT
}

$SIG{'ALRM'} = sub {
     print ("Nagios time-out\n");
     exit $ERRORS{"UNKNOWN"};
};

sub check_input {
    Getopt::Long::Configure ("bundling");
    GetOptions(
				'h'     => \$help,              		'help'                  => \$help,
                'u=s'   => \$username,                  'username=s'            => \$username,
				'l:s'	=> \$security_levelR1,			'seclev:s'				=> \$security_levelR1,
                'a=s'   => \$auth_protocol,             'authprotocol=s'        => \$auth_protocol,
                'A=s'   => \$auth_password,             'authpassword=s'        => \$auth_password,
                'x:s'   => \$priv_protocol,             'privprotocol:s'        => \$priv_protocol,
                'X:s'   => \$priv_password,             'privpassword:s'        => \$priv_password,
                'H=s'   => \$host,                      'hostname=s'            => \$host,
                'W=s'   => \$performance_warning_cpu, 		'warningcpu=s'      => \$performance_warning_cpu,
                'C=s'   => \$performance_critical_cpu,      'criticalcpu=s'    	=> \$performance_critical_cpu,
				'w=s'   => \$performance_warning_mem, 		'warningmem=s'      => \$performance_warning_mem,
                'c=s'   => \$performance_critical_mem,      'criticalmem=s'    	=> \$performance_critical_mem,
				'snmpv2'	=>	\$snmp_version,				'community:s'		=> \$community
        );

if ($help) { help(); exit $ERRORS{'OK'}; }
if (!defined($host)) { print "Unknown known host(s)\n"; usage(); exit $ERRORS{"UNKNOWN"}} else
{
    @hosts=split(/,/,$host);
    if ( scalar(@hosts) == 0) {print "Empty hosts lists"; usage(); exit $ERRORS{"UNKNOWN"}}
}
if ((!defined($username) || !defined($auth_password)) )
    { print "Put SNMP login info! (-h for help)\n"; usage(); exit $ERRORS{"UNKNOWN"}}
if (!defined($auth_protocol) || !defined($auth_password))
    { print "Put auth login info! (-h for help)\n"; usage(); exit $ERRORS{"UNKNOWN"}}
if (!defined($security_levelR1)) {
	if (!defined($priv_protocol) || !defined($priv_password))
		{ print "Put priv login info! (-h for help)\n"; usage(); exit $ERRORS{"UNKNOWN"}}
}
if (!defined($performance_warning_cpu) || !defined($performance_critical_cpu))
    { print "Put performance (warning/critical) for CPU! (-h for help)\n"; usage(); exit $ERRORS{"UNKNOWN"}}
if (!defined($performance_warning_mem) || !defined($performance_critical_mem))
    { print "Put performance (warning/critical) for Memory! (-h for help)\n"; usage(); exit $ERRORS{"UNKNOWN"}}
if (!defined($security_levelR1))
	{ $security_levelR1 = "authPriv"; }
if (!defined($snmp_version))
	{ $snmp_version = "snmpv3"; 
} elsif (!defined($community))
	{ print "Put community info! (-h for help)\n"; usage(); exit $ERRORS{"UNKNOWN"}}
}

######### MAIN PROGRAM

check_input();

if (defined($default_timeout)) {
  alarm($default_timeout);
}

######### Connect to specified host(s) and collect HSRP information using SNMP
foreach (@hosts) {
		my %credentials_local = create_credentials($_);
        if ( defined($username) && defined($auth_password)) {
				($session, $error) = Net::SNMP->session(
					%credentials_local
                );
                if (!defined $session) {
                        printf ("Probably wrong SNMP login information %s.\n", $error);
                        exit $ERRORS{"UNKNOWN"};
                } else {
                        my $result_cpu5min = $session->get_table(
                                Baseoid => $cpu5min_array{'cpu5min'}
                        );
						
						my $result_cpu1min = $session->get_table(
                                Baseoid => $cpu1min_array{'cpu1min'}
                        );
						
						my $result_cpu5sec = $session->get_table(
                                Baseoid => $cpu5sec_array{'cpu5sec'}
                        );

						my $result_cpuio_used = $session->get_table(
                                Baseoid => $memory_cpu_used_array{'memory_used_cpu'}
                        );

						my $result_cpuio_free = $session->get_table(
                                Baseoid => $memory_cpu_free_array{'memory_free_cpu'}
                        );
						
						my $host_name = $session->get_table(
                                Baseoid => $sysname_array{'sysname'}
                        );

                        if (!defined($host_name)) {
                                printf("Cannot fetch sysName from MIB (machine %s is down?): %s.\n", $_, $session->error);
                                $session->close;
                                exit $ERRORS{"UNKNOWN"};
                        } else {
                                foreach (oid_lex_sort(keys(%{$host_name}))) {
                                        $host_sysName = $host_name->{$_};
										my $char = '.';
										my $result = index($host_sysName, $char);
										if ($result != -1) {
											my $bgk_name = substr($host_sysName, 0, $result);
											$output_message = $output_message."$bgk_name ";
										} else {
											$output_message = $output_message."$host_sysName ";
										}
                                }
                        }

                        if ((!defined($result_cpu5min)) or (!defined($result_cpu5sec)) or (!defined($result_cpuio_used)) || (!defined($result_cpuio_free))) {
                                printf("Cannot fetch performance values from MIB (machine %s is down?): %s.\n", $_, $session->error);
                                $session->close;
                                exit $ERRORS{"UNKNOWN"};
                        } else {
						        foreach (oid_lex_sort(keys(%{$result_cpu5min}))) {
                                        $final_cpu5min = $result_cpu5min->{$_};
                                        $output_message2 = $output_message2."CPU5min=$final_cpu5min% ";
                                }
								foreach (oid_lex_sort(keys(%{$result_cpu1min}))) {
                                        $final_cpu1min = $result_cpu1min->{$_};
										$output_message2 = $output_message2."CPU1min=$final_cpu1min% ";
                                }
								foreach (oid_lex_sort(keys(%{$result_cpu5sec}))) {
                                        $final_cpu5sec = $result_cpu5sec->{$_};
										$output_message = $output_message."CPU5sec=$final_cpu5sec% ";
										$output_message2 = $output_message2."CPU5sec=$final_cpu5sec% ";
                                }
								
								foreach (oid_lex_sort(keys(%{$result_cpuio_used}))) {
                                        $final_cpuio_used = $result_cpuio_used->{$_};
										if ($licznik_cpuio_used == 0) {
											$output_message = $output_message."CPUMemUsed=$final_cpuio_used ";
											$output_message2 = $output_message2."CPUMemUsed=$final_cpuio_used ";
										} else {
											$output_message2 = $output_message2."I/OMemUsed=$final_cpuio_used ";
										}
										$licznik_cpuio_used++;
                                }
								foreach (oid_lex_sort(keys(%{$result_cpuio_free}))) {
                                        $final_cpuio_free = $result_cpuio_free->{$_};
										if ($licznik_cpuio_free == 0) {
											$output_message2 = $output_message2."CPUMemFree=$final_cpuio_free ";
											$cpu_free_performance = $final_cpuio_free;
										} else {
											$output_message2 = $output_message2."I/OMemFree=$final_cpuio_free ";
										}
										$licznik_cpuio_free++;
                                }
                        }
                }
        }
	$licznik_cpuio_used = 0;
	$licznik_cpuio_free = 0;
}

######### Handling warnings, errors and performance data

if (($final_cpu5min < $performance_warning_cpu)) { #OK
		getmaxerrorlevel(0);
} elsif (($final_cpu5min >= $performance_warning_cpu) and ($final_cpu5min < $performance_critical_cpu)) { #WARNING
        getmaxerrorlevel(1);
} elsif ($final_cpu5min > $performance_critical_cpu) { #CRITICAL
        getmaxerrorlevel(2);
}

if (($cpu_free_performance > $performance_warning_mem)) { #OK
		getmaxerrorlevel(0);
} elsif (($cpu_free_performance <= $performance_warning_mem) and ($cpu_free_performance > $performance_critical_mem)) { #WARNING
        getmaxerrorlevel(1);
} elsif ($cpu_free_performance < $performance_critical_mem) { #CRITICAL
        getmaxerrorlevel(2);
}

if ($error_level == 0) { #OK
        $output_message = $output_message."Error level : OK | $output_message2\n";
        print $output_message;
        exit $ERRORS{"OK"};
} elsif ($error_level == 1) { #WARNING
        $output_message = $output_message."Error level : WARNING | $output_message2\n";
        print $output_message;
        exit $ERRORS{"WARNING"};
} elsif ($error_level == 2) { #CRITICAL
        $output_message = $output_message."Error level : CRITICAL | $output_message2\n";
        print $output_message;
        exit $ERRORS{"CRITICAL"};
}
