#!/usr/pkg/bin/perl 
##
# $Header: /home/vikas/src/nocol/perlnocol/RCS/snmpgeneric,v 1.5 2000/03/21 21:28:57 vikas Exp $
#
#  snmpgeneric - perl monitor for generic SNMP variables.
# 	Directly monitors SNMP variables from the hosts listed.
#	Can query a single variable, or walk a tree and total up
#	the results, based on a perl regex that gets evaluated for
#	each variable returned.
#
#  AUTHOR:	 Ed Landa, elanda@comstar.net, May 1999
#
#####################
#
# DESCRIPTION HERE
#
# Supplemental Packages Required:
#
# snmpget
#
# Files used:
#
# Nocol event elements used:
#   sender                     "snmpgeneric"
#   severity                   as read from the config file
#   site
#    name                      the SNMP unit's name
#    addr                      the SNMP unit's IP address
#   var                       
#    name                      dependant on the config file
#    value                     1 means at Info level
#    threshold                 as read from the config file
#    units                     always ""
#
## 
##
#
############################
## Variables customization #  overrides values in the nocollib.pl library
############################
$nocolroot =  "/usr/pkg"   unless $nocolroot;	# SET_THIS
$etcdir  = "$nocolroot/etc"  unless $etcdir;	# location of config file
$bindir  = "$nocolroot/bin"  unless $bindir;

$snmpget  = "$bindir/snmpget" ;	        # location of snmpget  SET_THIS
$snmpwalk = "$bindir/snmpwalk";		# location of snmpwalk SET_THIS
#$mibfile = "$etcdir/mibII.txt" ;	# location of MIB file SET_THIS
$mibfile = "$etcdir/mib-v2.txt" ;	# location of MIB file SET_THIS
$ENV{"MIBFILE"}= $mibfile ;
$ENV{"MIBFILE_v2"}= $mibfile ;

$numtries = 2;   # number of times to try and connect before failing

############################
$debug = 0;				# set to 1 for debugging output
$libdebug = 0;				# set to 1 for debugging output
$prognm = $0;				# save program name

$varname="";
$varunits="" ;			# the var.units field in EVENT struct
$sleepint=60*5;       			# Seconds to sleep between tries.

require  "nocollib.pl" ;

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

##
# Read the config file. Use '\t' as a separator for 'item'
sub readconf
{
  local ($nets, $interface, $zone) ;

  open(CONFIG,"<$cfile")||die("Couldn't find $cfile, exiting");
  while(<CONFIG>)
  {
    chomp;
    if(/^\s*\#/) {next;}   # skip comments
    if(/^\s*$/) {next;}   # skip blank lines
    if (/\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s*$/)
    {   # this is an snmpget line
      $item="$1\t$2\t$4" ;	 # the name and address
      $oid{$item} = $3;
      $oidname{$item} = $4;
      $community{$item} = $5;
      $wlevel{$item} = $6;	# Warning level
      $elevel{$item} = $7;	# Error level
      $clevel{$item} = $8;	# Critical level
      push(@items,$item);
    }
    elsif (/\s*(\S+)\s+(\S+)\s+(\+\S+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s*$/)
      #                           ^^                                               ^^^^^
    {				# We're checking for a snmpwalk config line
      $item="$1\t$2\t$4" ;	# the name and address
      $oid{$item} = $3;
      $oidname{$item} = $4;
      $community{$item} = $5;
      $wlevel{$item} = $6;	# Warning level
      $elevel{$item} = $7;	# Error level
      $clevel{$item} = $8;	# Critical level
      $comp{$item} = $9;	# comparison variable
      push(@items,$item);
    }
    else
    {
      print "Ignoring illegal line: $_\n";
    }
    
  }		# end while(CONFIG)
  
  close(CONFIG);
  if ( 0 > $#items ) {
    die("Nothing to monitor in $cfile, exiting");
  }
  if ($debug) {
    print "Items are:\n";
    foreach (@items) {
      print "\t$_\n";
    }
  }
}	# end: sub(readconf)
  
  
## Check state of each 
##
#
sub dotest
{
  local ($host, $router) = @_ ;
  local ($acount, $isok) = (0, 0);
  
  # $host is the text hostname   $router is the IP
  # Check if a port number is attached to $router:$port
  ($router, $port) = split(/:/, $router, 2);

  if ($debug)
  {
    print "Checking $router\n";
  }
  
  -x $snmpget || die("Could not find executable $snmpget, exiting");
  -x $snmpwalk || die("Could not find executable $snmpwalk, exiting");
  
  if ($debug)
  {
    print "Active cmd= $walkactive\nType cmd= $walktype\n\n";
  }
  
  # If the OID starts with a plus then we walk the tree and add the values
  if ($oid{$item} =~ /^\+/)
  {
    my($myoid);
    
    $myoid=$oid{$item};		# get the OID ready
    $myoid =~ s/^\+(.*)$/\1/;	# remove the leading +

    if ($port) {
      $cmd = "$snmpwalk -p $port $router $community{$item} $myoid";
    }
    else {
      $cmd = "$snmpwalk $router $community{$item} $myoid";
    }      

    open (WALK, "$cmd |") || die "Could not run \"$cmd\"\n";
    while (<WALK>)
    {
      chomp;
      $active=$_;
      print "$active\n" if $debug;
      $active =~ s/^.*INTEGER:\s*(.*)$/\1/; # we only want the variable
      if ($active =~ /\(.*\)/)	# do we have a MIB match,  if so only get the numeric
      {
	$active =~ s/^.*\(\s*(\d+)\s*\).*$/\1/; # chop off the text descrip if there
      }
      print "active=$active\n" if $debug;
      $me = $comp{$item};
      $me =~ s/\*/$active/g;
      $me1 = eval $me;		# evaluate the string
      print "me=$me\n" if $debug;
      print "me1=$me1\n" if $debug;
      $acount += $me1;
      
    } 
    close(WALK);
    
  }
  else
  {
    $active="";
    $tries=$numtries;
    while ((! (($active =~ /INTEGER/)||($active =~ /Timeticks/)) ) && ($tries) )
    {
      if ($port) {
	$cmd = "$snmpget -p $port $router $community{$item} $oid{$item}";
      }
      else {
	$cmd = "$snmpget $router $community{$item} $oid{$item}";
      }
      print "cmd=$cmd\n" if $debug;
      $active = `$cmd`;
      print "$active" if $debug;
      $tries--;
    }
    if (! $tries)		# abort this check if we couldn't connect
    {
      return (-1, 0);
    }
    
    $active =~ s/^.*INTEGER:\s*(.*)$/\1/; # we only want the variable
    if ($active =~ /\(.*\)/)	# do we have a MIB match,  if so only get the numeric
    {
      $active =~ s/^.*\(\s*(\d+)\s*\).*$/\1/; # chop off the text descrip if there
    }
    $acount=$active;
    print "acount=$acount\n" if $debug;
    
    print "\n" if ($debug);
  }
  print "total acount=$acount\n" if $debug;
  
  if ($acount < 0)		# negative status to be ignored
  {
    return (-1, 0);
  }
  
  ($isok, $varthres{$item}, $maxseverity) = 
    &calc_status ($acount, $wlevel{$item}, $elevel{item}, $clevel{$item});
  
  print "(debug): Status $isok, MaxSev= $maxseverity\n" if $debug;
  return ($isok, $acount);
  
}				# end &dotest()


sub snmpgeneric_main
{
  &nocol_startup;
  &readconf;
  
  foreach $item (@items)
  {
    local ($host, $addr, $junk) = split( /\t/, $item );
    $varname=$oidname{$item};
    &init_event ($host, $addr, $item); # fill in initial values
  }
  
  while (1)
  {
    local ($stime, $deltatime);
    
    $stime = time;		# time starting tests
    
    foreach $item (@items)
    {
      local ($host, $addr, $junk) = split( /\t/, $item );
      local ($status, $value) = &dotest($host, $addr);
      
      if ($status < 0)		# bad status, probably some error
      {
	print STDERR "$me: dotest failed for $item... skipping\n";
	next;
      }
      else
      {
	&update_event($item, $status, $value, $maxseverity);
      }
    }
    open(OEVENTS,">$datafile");
    foreach $item (@items)
    {
      if (!$forget{$item})	# maintained by calling monitor
      {
	print "(DEBUG) writing '$item' to file\n" if $debug;
	&writeevent(OEVENTS, $item);
      }
    }
    close(OEVENTS);
    
    $deltatime = time - $stime;	# time to do tests
    
    if ($sleepint > $deltatime)
    {
      sleep($sleepint - $deltatime);
    }
    
  }				# end: while(1)
  
}				# end snmpgeneric_main()

###
### main
###

## We call our own main script so we can build different variable names

&snmpgeneric_main;


