#!/usr/bin/perl

########################################################################
#
# Check basic service of host
#
# Create by 2010.1.15
# Last modify  2010.8.10
#
########################################################################
 
use strict;
use warnings;
use Net::SNMP;
use DB_File;
use DB_File::Lock;
use Getopt::Long;
 
###################
## Init variables
###################
my $OID_CPU = ".1.3.6.1.4.1.2021.60.101";
my $OID_MEM = ".1.3.6.1.4.1.2021.4";
my $OID_SWAP = ".1.3.6.1.4.1.2021.11";
my $OID_LOAD = ".1.3.6.1.4.1.2021.10.1.3";
my $cpuUser       = $OID_CPU.".1";
my $cpuSystem     = $OID_CPU.".3";
my $cpuIdle       = $OID_CPU.".4";
my $cpuIowait     = $OID_CPU.".5";
my $swapIn        = $OID_SWAP.".62.0";
my $swapOut       = $OID_SWAP.".63.0";
my $memTotalReal  = $OID_MEM.".5.0";
my $memAvailReal  = $OID_MEM.".6.0";
my $memBuffer     = $OID_MEM.".14.0";
my $memCached     = $OID_MEM.".15.0";
my $memTotalSwap  = $OID_MEM.".3.0";
my $memAvailSwap  = $OID_MEM.".4.0";
my $load_1m       = $OID_LOAD.".1";
my $load_5m       = $OID_LOAD.".2";
my $load_15m      = $OID_LOAD.".3";
 
my @OIDS = ($cpuUser,$cpuSystem,$cpuIdle,$cpuIowait,$swapIn,$swapOut,
            $memTotalReal,$memAvailReal,$memBuffer,$memCached,$memTotalSwap,$memAvailSwap,
            $load_1m,$load_5m,$load_15m);
 
my $SNMP_COMMUNITY = "public";
my $SNMP_VERSION = "2c";
my $HOST = "";
my $TIME_OUT = 10;
 
## == CPU ==
my $cpuUsage_warning = 90;
my $cpuUsage_critical = 95;
my $iowait_warning = 4;
my $iowait_critical = 8;
 
## == Memory ==
my $used_warning = 90;
my $used_critical = 95;
my $swap_warning = 5;
my $swap_critical = 10;
 
## == Load ==
my $load_warning = 4;
my $load_critical = 8;
 
my ($perfdata,$output,$outputUnk,$outputCrit,$outputWarn,$outputOk) = ("","","","","","");
my $status = "";
my $BK = 0;
my $time_stp = time();
my %curr;
my $help;
 
#################################
## Processing command arguments
#################################
Getopt::Long::GetOptions(
    'host=s'        => \$HOST,
    'C=s'           => \$SNMP_COMMUNITY,
    'v=s'           => \$SNMP_VERSION,
    't=i'           => \$TIME_OUT,
    'help|h!'       => \$help,
    'cpu_w=i'       => \$cpuUsage_warning,
    'cpu_c=i'       => \$cpuUsage_critical,
    'iowait_w=i'    => \$iowait_warning,
    'iowait_c=i'    => \$iowait_critical,
    'used_w=i'      => \$used_warning,
    'used_c=i'      => \$used_critical,
    'swap_w=i'      => \$swap_warning,
    'swap_c=i'      => \$swap_critical,
    'load_w=i'      => \$load_warning,
    'load_c=i'      => \$load_critical);
 
if ($help || $HOST eq "")
{
    &usage();
    exit 1;
}
 
 
################################
## Get performance data by SNMP
################################
## Connect SNMP
my ($session, $error) = Net::SNMP->session(
                                -hostname  => $HOST,
                                -community => $SNMP_COMMUNITY,
                                -version   => $SNMP_VERSION,
                                -timeout   => $TIME_OUT);
if (!defined($session)) {
    print("UNKNOWN: SNMP Session : $error\n");
    exit 3;
}
 
## Get SNMP info
my $result = $session->get_request(-varbindlist => \@OIDS);
if (!defined($result))
{
    printf("UNKNOWN: %s.\n", $session->error);
    exit 3;
}
 
## Disconnect SNMP
$session->close();
 
my $saveData = $result->{$cpuUser}.":".$result->{$cpuSystem}.":".$result->{$cpuIdle}.":".
               $result->{$cpuIowait}.":".$result->{$swapIn}.":".$result->{$swapOut};
 
########################################
## Save performace data by BerkeleyDB
########################################
## Connect DB File
my %hash;
my $db;
&openDbFileConn();
 
if (!defined($hash{$HOST}))
{
    ## Save current cpu and swap to dbfile
    $hash{$HOST}=$saveData;
    undef $db;
    untie %hash;
    print "Wait a minute; ";
    exit 0;
}
 
## Get last cpu and swap from dbfile.
my %last;
my $lasts = $hash{$HOST};
 
## Save current cpu and swap to dbfile
$hash{$HOST}=$saveData;
 
undef $db;
untie %hash;
 
($last{$cpuUser},$last{$cpuSystem},$last{$cpuIdle},$last{$cpuIowait},$last{$swapIn},$last{$swapOut})=split(/:/,$lasts);
##############################
## Calculate CPU/MEMORY/LOAD
##############################
&calCpu();
 
&calMem();
 
&calLoad();
 
 
##################
## Notification
##################
if ($status =~ /Critical/)
{
    $output = "CRITICAL: ".$outputCrit;
    $BK = 2;
}elsif ($status =~ /Warning/)
{
    $output = "WARNING: ".$outputWarn;
    $BK = 1;
}elsif ($status =~ /Unknown/)
{
    $output = "UNKNOWN: ".$outputUnk;
    $BK = 3;
}else
{
    $output = "OK: ".$outputOk;
    $BK = 0;
}
$output =~ s/\;\s$//;
print "$output|$perfdata";
exit $BK;
 
 
######################
## Function
######################
## Calculate CPU
sub calCpu
{
 
    my $cpuTotal  = ($result->{$cpuUser} + $result->{$cpuSystem} + $result->{$cpuIdle} + $result->{$cpuIowait}) -
                    ($last{$cpuUser} + $last{$cpuSystem} + $last{$cpuIdle} + $last{$cpuIowait});
    my $cpuIdle   = $result->{$cpuIdle} - $last{$cpuIdle};
    my $cpuUser   = $result->{$cpuUser} - $last{$cpuUser};
    my $cpuSystem = $result->{$cpuSystem} - $last{$cpuSystem};
    my $cpuIowait = $result->{$cpuIowait} - $last{$cpuIowait};
 
    if ($cpuTotal > 0)
    {
        my $idle_per = $cpuIdle*100/$cpuTotal;
        my $user_per = $cpuUser*100/$cpuTotal;
        my $system_per = $cpuSystem*100/$cpuTotal;
        my $io_per = $cpuIowait*100/$cpuTotal;
        my $iowait_per = int($cpuIowait*100/$cpuTotal+0.5);
        my $cpuUsage_per = int($user_per + $system_per + $io_per + 0.5);
        my $str = "CPU:$cpuUsage_per% IOWAIT:$iowait_per%; ";
        if ($cpuUsage_per > $cpuUsage_critical || ($cpuUsage_per > 80 && $iowait_per > $iowait_critical))
        {
            $status .= "Critical: ";
            $outputCrit .= $str;
        }elsif ($cpuUsage_per > $cpuUsage_warning || ($cpuUsage_per > 80 && $iowait_per > $iowait_warning))
        {
            $status .= "Warning: ";
            $outputWarn .= $str;
        }else
        {
            $outputOk .= $str;
        }
        $perfdata .= "cpuUser=".sprintf("%0.2f",$user_per).
                     " cpuSys=".sprintf("%0.2f",$system_per).
                     " cpuIdle=".sprintf("%0.2f",$idle_per).
                     " cpuIOWait=".sprintf("%0.2f",$iowait_per)." ";
    }else
    {
        $status .= "Unknown: ";
        $outputUnk .= "total cpu unknown; ";
    }
}
 
## Calculate MEMORY
sub calMem {
    my $used_per=int(($result->{$memTotalReal}-$result->{$memAvailReal}-
                      $result->{$memBuffer}-$result->{$memCached})*100
                      /$result->{$memTotalReal}+0.5);
    my $str = "Memory(".&mem_convert($result->{$memTotalReal})."):$used_per% ";
 
    if ($result->{$memTotalSwap} == 0)
    {
        if ($used_per > $used_critical)
        {
            $status .= "Critical: ";
            $outputCrit .= $str;
        }elsif ($used_per > $used_warning)
        {
            $status .= "Warning: ";
            $outputWarn .= $str;
        }else
        {
            $outputOk .= $str;
        }
    }else
    {
        my $swapIn = $result->{$swapIn} - $last{$swapIn};
        my $swapOut = $result->{$swapOut} - $last{$swapOut};
        my $swap_per = int (($result->{$memTotalSwap} - $result->{$memAvailSwap}) * 100
                            / $result->{$memTotalSwap} + 0.5);
        $str .= "Swap(".&mem_convert($result->{$memTotalSwap})."):$swap_per%; ";
        if ( $swap_per > $swap_critical && $used_per > $used_critical && ($swapIn != 0 || $swapOut !=0) )
        {
            $status .= "Critical: ";
            $outputCrit .= $str;
        }elsif ($swap_per>$swap_warning && $used_per > $used_warning && ($swapIn != 0 || $swapOut !=0))
        {
            $status .= "Warning: ";
            $outputWarn .= $str;
        }else
        {
            $outputOk .= $str;
        }
    }
}
 
## Calculate LOAD
sub calLoad 
{
    my $str = "Load:".$result->{$load_1m}.",".$result->{$load_5m}.",".$result->{$load_15m};
 
    if ($result->{$load_1m} > $load_critical)
    {
        $status .= "Critical: ";
        $outputCrit .= $str;
    }elsif ($result->{$load_1m} > $load_warning)
    {
        $status .= "Warning: ";
        $outputWarn .= $str;
    }else
    {
        $outputOk .= $str;
    }
    $perfdata .= "load_1=$result->{$load_1m} load_5=$result->{$load_5m} load_15=$result->{$load_15m}";
}
 
 
sub mem_convert
{
    my $mem = shift;
    my $result;
    if($mem >= 1048576)
    {
        $result = int($mem/1024/1024 + 0.5);
        $result .= "G";
    }elsif($mem >= 1024)
    {
        $result = int($mem/1024 + 0.5);
        $result .= "M";
    }else
    {
        $result= $mem;
    }
    return $result;
}
 
## Open berkeleyDB connect 
sub openDbFileConn
{
    my $DB_PATH = "/opt/nagios/var/spool/performance";
    my $DB_FILE = $DB_PATH."/performance.db";
 
    if (! -d $DB_PATH) {
        mkdir($DB_PATH) || die "Cannot make dir $DB_PATH: $!";
    }
    $db = tie (%hash, "DB_File::Lock", $DB_FILE, O_CREAT|O_RDWR, 0666, $DB_BTREE, "write")
          || die "Cannot open DB_FILE $DB_FILE: $!";
}
 
sub usage
{
    print << "END";
Usage: ./check_performance.pl <option1> [option2]
 
Option1:
    -host          Host ip adrress
    
Option2:
    -C          SNMP community.(Default:public)
    -v          SNMP version.(Default:2c)
    -t          Connect SNMP timeout.(Default:10s)
    -cpu_w      Warning threshold for usage of CPU.(Default:90)
    -cpu_c      Critical threshold for usage of CPU.(Default:95)
    -iowait_w   Warning threshold for usage of CPU's iowait.(Default:4)
    -iowait_c   Critical threshold for usage of CPU's iowait.(Default:8)
    -used_w     Warning threshold for usage of memory.(Default:90)
    -used_c     Critical threshold for usage of memory.(Default:95)
    -swap_w     Warning threshold for usage of swap.(Default:5)
    -swap_c     Critical threshold for usage of swap.(Default:10)
    -load_w     Warning threshold for load.(Default:4)
    -load_c     Critical threshold for load.(Default:8)
END
}