#!/usr/local/bin/perl
#
# $Header: /home/vikas/src/nocol/perlnocol/RCS/novellmon,v 1.6 1999/11/01 13:19:07 vikas Exp $
#
#	novellmon - perl nocol Novell service monitor
#
# Date: September 21, 1993
# Programmer: John Wobus, jmwobus@mailbox.syr.edu
#  Modifications:  vikas@jvnc.net
#
#    (c) Syracuse University Computing & Network Services 1993
#
# No warranty is expressed or implied.  Permission to copy and use is
# extended to all.  Permission to redistribute is granted under the
# following conditions: it is not sold for profit; this copyright
# notice remains intact; the same permissions extend to the recipient;
# and if any changes are made, a notice is added so stating.
#
# Command Format:
#
#  novellmon
#
#    Automatically kills old process and forks a new one, reading
#    the configuration file in the process.
#
# What it does:
#
#    novellmon reads the list of Novell servers from a Cisco router and
#    checks for the appearance of the services listed in its own
#    configuration file and reports any that are missing.  Example:
#
#    Site      Address      Time   +-Variable-+ +-Value-+  Condition
#    DINAH  4(files)        09:58    IPX server        0    Critical
#
#    This line states that a file server called DINAH is not available.
#
# Files used:
#
#   rcisco                      perl program to do a Cisco router
#                               command remotely.
#   nocol/data/novellmon-output path to which to write nocol events.
#   novellmon-confg             configuration file.
#   novellmon.pid               file holding novellmon's current process id.
#
# Nocol event elements used:
#   sender                     "novellmon"
#   mon, day, hour, min        time at which entity went up or down
#   severity                   up: 4; down: 3,2,1; test & down: 2;
#   nocop                      up, down, unknown
#   site
#    name                      the Server name
#    addr                      the numerical type of service and an
#                               interpretation in parenthesis, e.g.
#                               "4(files)" for file service.
#   var                       
#    name                      "IPX server"
#    value                     1 means up, 0 means down
#    threshold                 always 2
#    units                     always "entry"
#
# To install this:
#   (1) Choose where to put this file and the above 4 files and
#       assign the perl variables below appropriately.
#   (2) Create your novellmon-confg file in its chosen place.
#   (3) Edit rcisco to include your Cisco router's password and put
#       rcisco in its chosen place.
#   (4) Put this file in its chosen place.
#   (5) Add appropriate code to rc.local to start this monitor.
#
# Configuration file format:
#    #<text>                                   Comment line.
#    router=<router>                           Name of Cisco router.
#    <servername> <servicetype>                IPX service, name & numerical
#                                               type.
#
# Sample configuration file:
#    # novellmon configuration
#    router=mycisco.excellent.edu
#    DINAH   4
#
##
# Router output (new Cisco routers)
# 
#  Type   Name              Net      Address        Port  Route Hops Interface
#  P      4 AG_COMM         4550280D.0000.0000.0001:0451  2/01  1    AT8/0.2
#  P+     4 AG_REG          4550150C.0000.0000.0001:0451  2/01  1    Et0/3
#  P      4 ALLIED_HEALTH   4550280A.0000.0000.0001:0451  2/01  1    AT8/0.2
#
# Old Cisco routers:
#
#  Type  Name  Net  Address      Port  Hops  Interface
#  4     SysOp 2a.0206.00a2.41ec:0450  2     Ethernet5
#
## 
##
#
#
############################
## Variables customization #  overrides values in the nocollib.pl library
############################
$rprog="./rcisco";		# Path for rcisco.
$rpasswd="";			# if NULL, uses the default in rcisco
# $rcommand="show ipx servers";	# on new Cisco versions
$rcommand="show novell servers";
$varname="IPX_server";		# Registered Novell Server
$varunits="Entry" ;		# the var.units field in EVENT structure
$sleepint=60*5;			# Seconds to sleep between tries.
############################
$debug = 0;			# set to 1 for debugging output
$libdebug = 0;			# set to 1 for library debug output
$prognm = $0 ;

require  "nocollib.pl" ;

$maxseverity = $E_ERROR ;	# max severity of events

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

# hash array of type numbers.
%tname=("4","files", "47","printing", "10C","net3270", "7050","ipxbootp");

##
# Read the config file. Use '\t' as a separator.
#
sub readconf {
    open(CONFIG,"<$cfile")||die("Couldn't find $cfile, exiting");
    while(<CONFIG>){
	chop;
	if(/^\s*#/) {next;}   # skip comments
	if(/^\s*$/) {next;}   # skip blank lines
	if(/^\s*router\s*=\s*(\S+)(\s.*)?$/) {$router=$1;}
	elsif(/^\s*(\S+)\s+(\S+)(\s.*)?$/) {push(@items,"$1\t$2");}
    }
    close(CONFIG);
    if(!$router){die("No router specified in $cfile, exiting")};
    if(0>$#items){die("Nothing to monitor in $cfile, exiting")};
}


## Check the current state of the router
#
sub dotest {
    local($loginok) = 0 ;
    foreach(@items){$found{$_}=0;}

    $command="$rprog $router ".' "'."$rpasswd".'" '.'"'."$rcommand".'"';
    if ($debug) {print "(debug) dotest: running command $command\n" ;}
    open(ROUTER,"$command|");

    while(<ROUTER>){
	tr/\r\n//d;
	if ( />/ ) {$loginok = 1 ;} # got the 'Router>' prompt
	# Old cisco output
	if(/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(\S+)$/) {
	    $type=$1; $name=$2; $addr=$3; $hops=$4; $interface=$5;
	    $item="$name\t$type";
	    $found{$item}=1;
	}
	# New Cisco output
	if(/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(\S+)$/) {
	    $type=$2; $name=$3; $addr=$4; $hops=$6; $interface=$7;
	    $item="$name\t$type";
	    $found{$item}=1;
	}
    }
    close(ROUTER);
    if ($loginok == 0) { print "Login into remote host failed\n" ;}
}


###
### Main program:
###

#Fork and get rid of old process.
&nocol_startup;

&readconf;

foreach $item (@items) {
    local($name,$type)=split(/\t/,$item);
    &init_event("$name", "$type(".$tname{$type}.")", $item);
}


while (1)
{
    &dotest;
    foreach $item (@items)
    {
	if ($found{$item}) { &update_event($item, 1, 1, $maxseverity); }
	else { &update_event($item, 0, 0, $maxseverity); }
    }
    #Note: we want to write the file quickly.
    open(OEVENTS,">$datafile");
    foreach $item (@items)
    {
	&writeevent(OEVENTS, $item);
    }
    close(OEVENTS);
    sleep($sleepint);
}
