#!/usr/local/bin/perl 
#
#        ciscomon - perl monitor for Cisco Routers
# $Header: /home/vikas/src/nocol/perlnocol/RCS/ciscomon,v 1.2 1999/11/01 05:54:25 vikas Exp $
#
# This script uses rcisco to telnet into a Cisco router and can query
# various Cisco specific parameters such as 
#	CPU usage
#	Airflow & Temperature
#	Voltages
#	Memory utilzation
# The router names, addresses and passwords are specified in the config
# file, along with the thresholds for each parameter. You can also specify
# a default.
#
# Part of the NOCOL monitoring package.
#
## Contributed by Mathias Koerber, SingNet, mathias@singnet.com.sg, May 96
#  Derived from bgpmon v1.3
#
## 
##
#
#
############################
## Variables customization #  overrides values in the nocollib.pl library
############################
$rprog="rcisco";                        # Path for rcisco.
$rpasswd="";                            # if NULL, uses the default in rcisco
$sleepint=60*10;                        # Seconds to sleep between tries.
$sender="ciscomon";
############################
$debug = 0;                             # set to 1 for debugging output
$libdebug = 0;                          # set to 1 for debugging output
$prognm = $0;                           # save program name

require  "nocollib.pl" ;

$maxseverity = $E_CRITICAL ;

local($vpad) = "" ;

#
#
$vname{"cpuusage"}      = "CPUusage/5m";
$vunits{"cpuusage"}     = "Percent";
$rcommand{"cpuusage"}   = "show processes";
$match{"cpuusage"}      = '^CPU utilization for five seconds: \d+%/\d+%; one minute: \d+%; five minutes: (\d+)%';

$vname{"airflow"}       = "Airflow";
$vunits{"airflow"}      = "Deg(C)";
$rcommand{"airflow"}    = "show env all";
$match{"airflow"}       = '^\s*Airflow\s+temperature\s+measured\s+at\s+([+-.\d]+)\(C\)\s*$';

$vname{"inlet"}         = "Inlet";
$vunits{"inlet"}        = "Deg(C)";
$rcommand{"inlet"}      = "show env all";
$match{"inlet"}         = '^\s*Inlet\s+temperature\s+measured\s+at\s+([+-.\d]+)\(C\)\s*$';
#$match{"inlet"}        = '^\s*Inlet\s+temperature\s+measured\s+at\s+([+-.\d]+)\(C\)\s*$';
$match{"inlet"}         = '^\s*chassis\s+inlet\s+measured\s+at\s+([+-.\d]+)C.*$';


$vname{"v+12"}          = "+12V";
$vunits{"v+12"}         = "mVolt";
$rcommand{"v+12"}       = "show env all";
$match{"v+12"}          = '^\s*\+12\s+volts\s+measured\s+at\s+([+-.\d]+)\(V\)\s*$';

$vname{"v+5"}           = "+5V";
$vunits{"v+5"}          = "mVolt";
$rcommand{"v+5"}        = "show env all";
$match{"v+5"}           = '^\s*\+5\s+volts\s+measured\s+at\s+([+-.\d]+)\(V\)\s*$';

$vname{"v-12"}          = "-12V";
$vunits{"v-12"}         = "mVolt(-)";
$rcommand{"v-12"}       = "show env all";
$match{"v-12"}          = '^\s*\-12\s+volts\s+measured\s+at\s+[+-]([.\d]+)\(V\)\s*$';

$vname{"v+24"}          = "+24V";
$vunits{"v+24"}         = "mVolt";
$rcommand{"v+24"}       = "show env all";
$match{"v+24"}          = '^\s*\+24\s+volts\s+measured\s+at\s+([.+-\d]+)\(V\)\s*$';

$vname{"memory"}        = "ProcMem_used";
$vunits{"memory"}       = "Percent";
$rcommand{"memory"}     = "show memory free";
$match{"memory"}        = '^\s*Processor\s+\S+\s+\S+\s+(\d+)\s+([\d]+)\s+(\d+)\s*.*$';



-x $rprog || die("Could not find executable $rprog, exiting");

$levent = length( pack($event_t, 0, '') );          # sizeof structure

##
# Read the config file. Use '\t' as a separator for 'item'
sub readconf {
    local ($var);
    local ($host);

    undef %wthresh;
    undef %ethresh;
    undef %cthresh;
    undef %variables;

    open(CONFIG,"<$cfile")||die("Couldn't find $cfile, exiting");
    while(<CONFIG>)
    {
        chop;
        undef $var;
        if(/^\s*#/) {next;}   # skip comments
        if(/^\s*$/) {next;}   # skip blank lines
        if (/^(default)\s*(\S*)$/i) {
            $host = default;    # do not push !!
            $passwd{$host} = $2 if $2;
            next;
        }
        if (/^sleep:\s*(\d+)/) {
                $sleepint = $1;
                next;
                }
        if (/^(\S+)\s+(\S+)\s*(\S*)$/) # must start at beginning of line
        {
            $host="$1\t$2" ;     # the name and address
            $passwd{$host} = $3 if $3;
            push (@hosts,$host);
            next;
        } elsif (/^\s+(\S+)\s+([+-.\d]+)\s+([+-.\d]+)\s+([+-.\d]+)\s*$/) # continuation line, variable & 3 thresholds
           {
            $var = $1;
            $var =~ tr/A-Z/a-z/;
            $allvars{$var} = 1;
            $item = "$host\t$var";
            $wthresh{$item} = $2;
            $ethresh{$item} = $3;
            $cthresh{$item} = $4;
            next if ($host eq "default");
            $variables{$item} = 1;
            $severity{$item} = $E_INFO;
            ($h,$a,$v) = split(/\t/,$item);
            ($mon{$item},$day{$item},$hour{$item},$min{$item}) = &gettime ;
            $sender{$item}=$sender;
            ($sitename{$item},$siteaddr{$item}) = split(/\t/,$host);
            $varname{$item}  = $vname{$var};
            $varvalue{$item} = 0;
            $varthres{$item} = 0;
            $varunits{$item} = $vunits{$var} ;
            $severity{$item} = $E_INFO;
            $loglevel{$item} = $E_INFO;
            $nocop{$item}    = $nocop{$item} | $n_UNKNOWN ;
            push(@items,$item);
            next;
        } elsif (/^\s+(\S+)\s*/)
          {
           $var = $1;
           # no thresholds given , use defaults
            if ($host eq "default") {
                print STDERR "cannot use defaults for default (var=$var)\n";
                next;
                }
            $var =~ tr/A-Z/a-z/;
            $allvars{$var} = 1;
            $item = "$host\t$var";
            $wthresh{$item} = $wthresh{"default\t$var"};
            $ethresh{$item} = $ethresh{"default\t$var"};
            $cthresh{$item} = $cthresh{"default\t$var"};
            $variables{$item} = 1;
            ($h,$a,$v) = split(/\t/,$item);
            ($mon{$item},$day{$item},$hour{$item},$min{$item}) = &gettime ;
            $sender{$item}=$sender;
            ($sitename{$item},$siteaddr{$item}) = split(/\t/,$host);
            $varname{$item}  = $vname{$var} ;
            $varvalue{$item} = 0 ;
            $varthres{$item} = 0 ;
            $varunits{$item} = $vunits{$var} ;
            $severity{$item} = $E_INFO;
            $loglevel{$item} = $E_INFO;
            $nocop{$item}    = $nocop{$item} | $n_UNKNOWN ;
            push(@items,$item);
            next;
        }
        else {print "Ignoring illegal line: $_\n";}

    }   # end while(CONFIG)

    close(CONFIG);
    if(0>$#hosts){die("Nothing to monitor in $cfile, exiting")};
    if ($debug) {
        print "Items are:\n"; foreach (@items) { print "\t$_\n" } ;
    }
}                               # end: readconf


&nocol_startup;
&readconf;

local ($stime, $deltatime);

## Check state of each router
#
while (1) {
    local ($host, $router) = @_ ;

    $stime = time;

#    open(OEVENTS,">$datafile");

    for $h (@hosts ) {
        local (%cmdused);
        local ($loginok) = 0;
        local (@result);
        local (@vv);
        local ($v);
        ($host,$router) = split(/\t/,$h);

    if ($debug) { print "Checking $router\n"; }
    $upasswd = ($passwd{$h} ? $passwd{$h} : ($passwd{"default"} ? $passwd{"default"} : $rpasswd));
    $command="$rprog $router ".' "'."$upasswd".'" "';
    for $v (keys %allvars) {
             $item = "$h\t$v";
            if (($variables{$item}) && (!$cmdused{$rcommand{$v}})) {
                $command .="\n$rcommand{$v}";
                $cmdused{$rcommand{$v}}=1;
                }
        }
    $command .='" ';
    if ($debug) {print "(debug) dotest: running command $command\n" ;}

    open (ROUTER, "$command |") ;
        
    while(<ROUTER>) {
        next if /^\s*$/;
        next if /terminal length/i;
        next if /User Access Verifi/i;
        next if /password/i;
        tr/\r\n//d;
        if ( />/ ) {$loginok = 1 ; next} # got the 'Router>' prompt
        for $v (keys %allvars) {
                if (@r = m|$match{$v}|i) {
                        
                        if ($v =~ /memory/) {
                                # the memory matchline returns 3 values...
                                next if ($r[0] == 0);   # can't divide :-(
                                $pc = ($r[1])/($r[0])*100;      # percentage used..
                                push(@result,$v,$pc);
                                }
                        elsif ($v =~ /v[+-][\d]+/i) {
                                # ah, a voltage. we'll multiply by 10 and abs()
                                $vl = $r[0]*1000;
                                $vl *= -1 if ($vl < 0); # negative voltages
                                push(@result,$v,$vl);
                                }
                        else {
                                # default, just one value
                                push(@result,$v,$r[0]);
                                }
                        next;
#           if ($debug) {print "(debug) processing line: $_\n" ;}
                }
                elsif ($debug) {
#           print "(debug) skipping line: $_\n" ;
                }
        }
    }  # end while
    close (ROUTER);

    if ($loginok == 0) { 
        print "Login into remote host $router failed\n" ;
        next;

    }
    while (($#result >= 0)) {
            
            $var        = shift(@result);
            $value      = shift(@result);
            $item = "$host\t$router\t$var";
            $varvalue{$item} = $value;
            #
            # special handling for temperature.. wthresh is used as a low warning....
            #
            if ($var =~ /Airflow|Inlet/i) {
                if ($value < $wthresh{$item}) {
                        $isok = 0;
                        $maxseverity = $E_WARNING;
                        $varthres{$item} = $wthresh{$item};
                        }
                elsif ($value > $cthresh{$item}) {
                        $isok = 0;
                        $maxseverity = $E_CRITICAL;
                        $varthres{$item} = $cthresh{$item};
                        }
                elsif ($value > $ethresh{$item}) {
                        $isok = 0;
                        $maxseverity = $E_ERROR;
                        $varthres{$item} = $ethresh{$item};
                        }
                else {
                        $isok = 1;
                        $maxseverity = $E_INFO;
                        $varthres{$item} = $wthresh{$item};
                        }
                }
            # CPUusage and positive voltages...follow the standard...
            elsif ($var =~ /^v[+-][\d]+|CPUusage/i) {
                    ($isok,$varthres{$item},$maxseverity) = &calc_status($value,$wthresh{$item},$ethresh{$item},$cthresh{$item});
                }
            else {
                    ($isok,$varthres{$item},$maxseverity) = &calc_status($value,$wthresh{$item},$ethresh{$item},$cthresh{$item});
                }
            #
            if ($maxseverity < $E_CRITICAL) { $maxseverity = $E_CRITICAL;}

            if ($isok)        # status is UP
            {
                ($mon{$item},$day{$item},$hour{$item},$min{$item}) = &gettime ;
                if (!($nocop{$item} & $n_UP))                      # recent state change
                {
                    $nocop{$item} = $nocop{$item} & ~($n_UP | $n_DOWN | $n_UNKNOWN) | $n_UP;
                    $loglevel{$item} = $severity{$item} ;     # loglevel set to old level
                    $severity{$item} = $E_INFO;
                    &eventlog(&packevent($item)) ;         # log to noclogd daemon

                }
            }
            else                # status is DOWN, escalate severity
            {
                local($oseverity) = $severity{$item} ;
                # escalate severity
                $severity{$item}= ($severity{$item} > $maxseverity) ? ($severity{$item} - 1) : $maxseverity;

                $nocop{$item}= $nocop{$item} & ~($n_UP | $n_DOWN | $n_UNKNOWN) | $n_DOWN;

                if ($oseverity != $severity{$item}) # severity change
                {
                    ($mon{$item},$day{$item},$hour{$item},$min{$item}) = &gettime ;
                    # smaller severity is more severe... set  that as loglevel
                    $loglevel{$item}= $severity{$item} < $oseverity ? $severity{$item}:$oseverity;
                    &eventlog(&packevent($item));
                }
             }

           }

        }
        open(OEVENTS,">$datafile");
        foreach $item (@items)
        {
            if(!$forget{$item})
            {
                &writeevent(OEVENTS, $item);
            }
        }
        close(OEVENTS);

        $deltatime = time - $stime;             # time to do tests

        if ($sleepint > $deltatime) { sleep($sleepint - $deltatime); }

} # end: while(1)



###
### main
###

#&nocol_main ;

