| [Date Prev] [Date Next] | [Thread Prev] [Thread Next] | [Date Index] [Thread Index] |
Re: nocollib.pl
|
I just noticed that nocollib.pl is supposed to be a lot bigger than 61
lines...
jonz@cartman.netrail.net(79) % wc -l nocollib.pl
573 nocollib.pl
can you verify that your file is that size? just incase you have a
corrupt file, I've attached my copy of nocollib.pl which works fine.
On Mon, 28 Jun 1999, Steve Nash wrote:
> Well now, Since I appear to be having the same problem, here:
>
> # bgpmon
> nocollib.pl did not return a true value at bgpmon line 62.
>
> that is after making all apropriate changes....
>
> Any suggestions?
>
>
> Shawn O'Hail wrote:
>
> > put
> >
> > return 1;
> >
> > on a line by it's self at the end of nocollib.pl
> >
>
> --
> \\|//
> -(@ @)-
> ==oOO==(_)==OOo======================================================
> Steve Nash uin: 9021398
> snash@lightning.net
> Senior Network Architect
> Lightning Internet Services LLC http://www.lightning.net
>
>
>
Thank you,
Jonathan A. Zdziarski
Sr. Systems Administrator
Netrail, inc.
888.NET.RAIL x240
#!/usr/bin/perl5
#
# $Header: /home/vikas/src/nocol/perlnocol/RCS/nocollib.pl,v 1.12 1998/10/02 19:20:54 vikas Exp $
#
# nocollib.pl - perl library of NOCOL routines
#
#
# Initially derived from the perl modules submitted by John Wobus,
# jmwobus@mailbox.syr.edu 9/21/93 (see novellmon, armon)
#
# This rewrite as a NOCOL perl library by Vikas Aggarwal 1994 - 1997
# All current NOCOL development undertaken and maintained by vikas@navya.com
#
## The following is a list of associative arrays used globally to
# refer to the fields in the EVENT structure.
# sender, sitename, siteaddr,
# varname, varval, varthres, varunits,
# mon, day, hour, min, severity, loglevel, nocop
#
# Define $libdebug=1 to turn on verbose debugging messages.
# Might need to fix the '$event_t' description for null padding
# (since some systems might align structure fields on different
# boundaries). Use the 'utility/show_nocol_struct_sizes.c' program
# to see the size of various fields on your system.
#
# Usage:
#
# require "nocollib.pl";
#
#
# Subroutines:
#
# unpackevent - Extracts packed EVENT fields into various arrays
# packevent - Converts array fields into a packed EVENT structure
# readevent - Read EVENT from open file desc and unpack it.
# writeevent - Pack various arrays into EVENT struct and write out.
# nocol_startup - Forks off and creates a new PID file, etc.
# standalone - Kill earlier running processes and setup signals
# init_event - Fill in various arrays with initial (global) values
# update_event - Given status, updates array fields and logs if needed
# eventlog - Logs event to 'noclogd' daemon
#
#
####################################################################
#
#######################
## Customize these ##
#######################
$nocolroot = "/usr/local/nocol" unless $nocolroot; # SET_THIS
$etcdir = "$nocolroot/etc" unless $etcdir; # location of config file
$piddir = "/usr/local/nocol/run" unless $piddir; # SET_THIS
$bindir = "$nocolroot/bin" unless $bindir;
$datadir = "$nocolroot/data" unless $datadir; # output data file
push(@INC, $bindir); push(@INC, $etcdir); # add to search paths for 'require'
$ENV{'PATH'} .= ":$bindir"; # add to path for snmpwalk, etc.
$NLOG_HOST = "cartman.netrail.net" ; # Used for logging to noclogd, SET_THIS
$NLOG_SERVICE = "noclog" ; # if port is in /etc/services
$NLOG_PORT = 5354 unless $NLOG_PORT; # default port if NOT in /etc/services
$HOSTMON_SERVICE = "hostmon" unless $HOSTMON_SERVICE; # for 'hostmon'
$HOSTMON_PORT = 5355 unless $HOSTMON_PORT; # used if not in /etc/services
$ping = "/bin/ping" ; # SET_THIS to ping location
$rpcping = "$bindir/rpcping" unless $rpcping; # SET_THIS, used by 'hostmon'
## Need to pad the following for pack() using 'x' nulls (actual length is 195,
# but C compilers have to align on word? boundary).
# event_t is the EVENT structure format, notice the nulls for ascii strings
# The last 'x' is a padding to align depending on machine architecture.
# Use the utility/show_nocol_struct_sizes to see the size on your arch.
# NOTE : Use 'A' instead of 'a' as unpacking 'a' will not remove any
# trailing blanks or spaces whereas in case of 'A' it does.
$event_t = "a11 x a15 x a127 x a15 x L L a7 x CCCC C C C x" ; # SET_THIS
$levent = length( pack($event_t, 0, '') ); # sizeof structure
if ($libdebug) {
print STDERR "(libdebug) Sizeof event= $levent\n" ;
print STDERR "\tNocol Dir= $nocolroot, LOGhost= $NLOG_HOST\n" ;
}
######################
## GLOBAL DEFINES ## Extracted from nocol.h
######################
$E_CRITICAL = 1;
$E_ERROR = 2;
$E_WARNING = 3;
$E_INFO = 4;
$n_UP = 0x01;
$n_DOWN = 0x02;
$n_UNKNOWN = 0x04;
$n_TEST = 0x08;
$n_NODISPLAY = 0x10;
$varname = "UNSET" unless $varname;
$varunits = "UNSET" unless $varunits;
$sleepint = 5*60 unless $sleepint;
## these variables are needed by eventlog()
$nlogfd = -1;
$nlogclosetime = -1; # used for deciding when to reopen logfile
###################################################################
# Support routines for Networking
###################################################################
##
# Create a connected socket to the remote host.
# newSocket ("cisco-gw.abc.com", 23, 'tcp')
# Dies on failure.
sub newSocket {
local ($host, $port, $sproto) = @_ ;
local ($type, $proto, $haddr);
$sproto = 'tcp' unless $sproto;
# Depending on version of perl, call 'use Socket' or 'require socket.ph'
# From Netnews posting by jrd@cc.usu.edu (Joe Doupnik)
local ($AF_INET, $SOCK_STREAM, $SOCK_DGRAM) = (2, 1, 2); # default values
if ( $] =~ /^5\.\d+$/ ) { # perl v5
# print STDERR "debug: Check for perl5 passed...\n";
eval "use Socket";
$AF_INET = &Socket'PF_INET; #'
$SOCK_STREAM = &Socket'SOCK_STREAM; #'
$SOCK_DGRAM = &Socket'SOCK_DGRAM; #'
}
else { # perl v4
eval {require "socket.ph"} || eval {require "sys/socket.ph"} ;
if ( defined (&main'PF_INET) ) { #')) {
# print STDERR "debug: found sys/socket.ph\n";
$AF_INET = &main'PF_INET; #'
$SOCK_STREAM = &main'SOCK_STREAM; #';
$SOCK_DGRAM = &main'SOCK_DGRAM; #';
}
# Solaris, need to run h2ph on include/socket.h to create socket.ph
elsif (`uname -s -r -m` =~ /SunOS\s+5/) {
require "sys/socket.ph"; # Gives error and exits
die 'Did you forget to run h2ph ??';
}
}
if ($port == 0 || $port =~ /\D/) {
($junk,$junk,$port) = getservbyname($port, $sproto);
}
if (! $port) {
print STDERR "No port number (is entry needed in /etc/services ?)\n";
return -1;
}
if ($sproto =~ /tcp/) { $type = $SOCK_STREAM;}
else { $type = $SOCK_DGRAM };
# Do equivalent of a inet_ntoa()
if ($host =~ /^\d/) {
local ( @n ) = split(/\./, $host);
$haddr = pack('C4', @n);
}
else { ($junk,$junk,$junk,$junk, $haddr) = gethostbyname($host); }
if (! $haddr) {
print STDERR "Unknown host (no address)- $host\n";
return -1;
}
$paddr = pack ('S n a4 x8', $AF_INET, $port, $haddr);
($junk, $junk, $proto) = getprotobyname($sproto);
socket(SOCK, $AF_INET, $type, $proto) || die "socket: $!";
if (! connect(SOCK, $paddr)) {
close SOCK;
print STDERR "newSocket() connect failed: $!\n";
return -1;
}
return (SOCK);
}
########################################################################
### NOCOL subroutines
########################################################################
##
##
# Given an index (to the list of associative arrays that are globally
# declared), and an event structure, it unpacks and fills in the arrays
# with the values from the event structure.
sub unpackevent {
local($i, $event) = @_ ; # index and event
local($vpad, $uevent_t);
# $uevent_t is required because in the original event_t
# we have used 'a' for packing to put NULL padding. This
# is required for C programs to read this structure. But
# while unpacking we have to use 'A' so that it removes
# any trailing spaces or NULLs. So we are converting
# 'a' to 'A'.
($uevent_t = $event_t) =~ tr/a/A/;
($sender{$i},$sitename{$i},$siteaddr{$i},
$varname{$i},$varvalue{$i},$varthres{$i},$varunits{$i},
$mon{$i},$day{$i},$hour{$i},$min{$i},
$severity{$i},$loglevel{$i},$nocop{$i}, $vpad)
=unpack($uevent_t, $event);
($libdebug > 0) && print "(libdebug) unpackevent: $i\n";
}
##
# Given an index (to the list of associative arrays that are globally
# declared), it creates an EVENT structure and returns it.
# Note the 'vpad' to align the structure on an even byte boundary.
sub packevent {
local($i) = @_ ; #index to associative arrays
local($event) ;
local($vpad) = "" ;
$event = pack($event_t,
$sender{$i},$sitename{$i},$siteaddr{$i},
$varname{$i},$varvalue{$i},$varthres{$i},$varunits{$i},
$mon{$i},$day{$i},$hour{$i},$min{$i},
$severity{$i},$loglevel{$i},$nocop{$i}, $vpad) ;
return($event) ;
}
##
## Subroutines to read and write from the datafile.
#
sub readevent {
local($fd, $index) = @_ ; # open file descriptor & index
local($bl,$event);
$index = 'TEMP' unless $index ; # use TEMP storage by default
if ($bl = read($fd, $event, $levent)) {
&unpackevent($index, $event); # fills in the various arrays
}
else {
$debug && print STDERR "(dbg)readevent():No data(Read returned $bl)\n";
}
return($bl);
}
sub writeevent {
local($fd, $index) = @_ ; # open file descriptor & index
local($event) = &packevent($index);
print $fd $event ;
}
##
# printevent() to display the event arrays given an index
sub printevent {
local($i) = @_ ;
print "
SENDER= $sender{$i}, $sitename{$i},$siteaddr{$i},
VAR= $varname{$i},$varvalue{$i},$varthres{$i},$varunits{$i},
DATE= $mon{$i},$day{$i},$hour{$i},$min{$i},
SEV= $severity{$i},$loglevel{$i}, $nocop{$i}\n" ;
}
## gettime()
#
# If the global variable '$eventime' is set, then use its value (the
# 'dotest' subroutine could have set this.
sub gettime {
local($mon,$day,$hour,$min,@timesecs);
if ($eventtime > 0) {@timesecs = localtime($eventtime); }
else {@timesecs=localtime(time); }
$mon=substr("00".(1+$timesecs[4]), -2);
$day=substr("00".$timesecs[3], -2);
$hour=substr("00".$timesecs[2], -2);
$min=substr("00".$timesecs[1], -2);
return($mon,$day,$hour,$min);
}
## nocol_startup()
# Forks and creates the pid file. Does some preliminary stuff also.
#
sub nocol_startup {
$prognm = $0 unless $prognm; # set to the name of program
@me=split(/\//,$prognm); $me=pop(@me);
#$piddir=join("/",@me); if ($piddir eq "") {$piddir=$etcdir;}
$piddir=$piddir unless $piddir;
$cfile="$etcdir/$me-confg" unless $cfile;
$datafile="$datadir/$me-output" unless $datafile;
$sender= $me unless $sender; # filled in the EVENT sender
$ostype= `uname -s -r -m` unless $ostype; # OS, revision, arch
chop($ostype);
($libdebug > 1) && print STDERR "(libdebug) me= $me, sender= $sender\n" ;
if ( (!$debug) && ($p= fork)) {print "$p\n"; exit;}
&standalone($me, $piddir);
}
## standalone()
# Checks to see if PIDFILE exists and kills any earlier running process.
# Created new PIDFILE and sets up signal handlers. Incidentally, pidfile
# cannot be local since it is unlinked by the signal handler routines.
#
sub standalone {
local($me,$dir)=@_;
local($localhost)=`hostname`; chop ($localhost);
local($pid,$host);
local($PSCMD) = "ps"; # cmd to see process by giving a pid
local ($status) = grep(/usage/i, `$PSCMD 1 2>&1`);
if ($status == 1) { $PSCMD = "ps -p" ;}
$pidfile= "$dir/$me.pid"; # cannot be local()
if(open(PID,"<$pidfile"))
{
chop($pid=<PID>); chop($host=<PID>); close(PID);
if ("$host" ne "$localhost") {
die("Program probably running on $host, else delete $pidfile\n");
}
if($pid =~ /^\d+$/)
{
for (1..2) { # try killing twice
foreach (`$PSCMD $pid`) {
chop;
if(/$pid.*$me/){kill(9,$pid); print "killing process $pid\n"; }
} # end: foreach()
} # end: for(1..2)
}
} # end: open(PID...)
if (open(PID,">$pidfile")){print PID "$$\n$localhost\n"; close(PID);}
else {die ("standalone: cannot create $pidfile, $!\n") } ;
$SIG{"QUIT"} = clean_out ;
$SIG{"TERM"} = clean_out ;
$SIG{"INT"} = clean_out ;
$SIG{"USR1"} = toggle_libdebug ;
}
sub clean_out {
unlink $pidfile ;
unlink $datafile ;
die "Terminating on signal\n" ;
}
sub toggle_libdebug {
$libdebug = ++$libdebug % 3 ; # increment to 2, then back to 0
if ($libdebug) { print STDERR "(nocollib): libdebug = $libdebug\n"; }
}
## Fill in default values for the item arrays. Inserts the following 'global'
# variables: $sender $varname $varunits
# Gets the sitename/siteaddr from the args passed to it.
sub init_event {
local($sitename, $siteaddr, $i) = @_ ; # index into assoc arrays
if ($libdebug) {
print STDERR "(libdebug) init_event: Inserting index= $i, Sitename= $sitename, Siteaddr= $siteaddr\n"; }
$siteaddr = '-' if ($siteaddr eq '');
if ($sender eq "") {die("init_event: Bad sender= $sender\n"); }
$sender{$i} = $sender ;
$sitename{$i} = $sitename ;
$siteaddr{$i} = "$siteaddr";
$varname{$i} = $varname ;
$varvalue{$i} = 0 ;
$varthres{$i} = 0 ;
$varunits{$i} = $varunits ;
($mon{$i},$day{$i},$hour{$i},$min{$i}) = &gettime ;
$severity{$i} = $E_INFO;
$loglevel{$i} = $E_INFO;
$nocop{$i} = $nocop{$i} | $n_UNKNOWN ;
} # end init_event()
## calc_status()
# Useful to extract the status and maximum severity in monitors which
# have 3 thresholds. Given the three thresholds and the value, it returns
# the 'status, thres, maxseverity'.
# Handle increasing or decreasing threshold values.
sub calc_status {
local ($val, $warnt, $errt, $critt) = @_ ; # the value and 3 thresholds
local ($status) = 1;
local ($gt) = 1 ; # test if value *greater* than thresholds
if ($critt < $warnt) { $gt = 0 ;} # test if value *less* than thres
if ( ($gt && $val >= $warnt) || ($gt == 0 && $val <= $warnt) )
{ $status = 0; } # value exceeds warning threshold
if ( ($gt && $val >= $critt) || ($gt == 0 && $val <= $critt) )
{ return ($status, $critt, $E_CRITICAL); }
elsif ( ($gt && $val >= $errt) || ($gt == 0 && $val <= $errt) )
{ return ($status, $errt, $E_ERROR); }
elsif ( ($gt && $val >= $warnt) || ($gt == 0 && $val <= $warnt) )
{ return ($status, $warnt, $E_WARNING); }
else
{ return ($status, $warnt, $E_INFO); } # $status should be UP
} # end calc_status
## update_event()
# Given index to events, status (0 or 1), new value, max severity to escalate
# to, this subroutine will update the various associative arrays and log the
# event also (if the state has changed).
sub update_event {
local($i, $status, $value, $maxsev) = @_ ; # $i is index to arrays
if ($libdebug) {
print STDERR "(libdebug) update_event: ITEM $i, stat=$status, maxsev=$maxsev, val= $value\n";
}
if ($maxsev < $E_CRITICAL) { $maxsev = $E_CRITICAL; }
$varvalue{$i} = $value ;
if ($status) # status is UP
{
($mon{$i},$day{$i},$hour{$i},$min{$i}) = &gettime ;
if (!($nocop{$i} & $n_UP)) # recent state change
{
$nocop{$i} = $nocop{$i} & ~($n_UP | $n_DOWN | $n_UNKNOWN) | $n_UP;
$loglevel{$i} = $severity{$i} ; # loglevel set to old level
$severity{$i} = $E_INFO;
&eventlog(&packevent($i)) ; # log to noclogd daemon
}
}
else # status is DOWN, escalate severity
{
local($oseverity) = $severity{$i} ;
# escalate severity
$severity{$i}= ($severity{$i} > $maxsev) ? ($severity{$i} - 1) : $maxsev;
$nocop{$i}= $nocop{$i} & ~($n_UP | $n_DOWN | $n_UNKNOWN) | $n_DOWN;
if ($oseverity != $severity{$i}) # severity change
{
($mon{$i},$day{$i},$hour{$i},$min{$i}) = &gettime ;
# smaller severity is more severe... set that as loglevel
$loglevel{$i}= $severity{$i} < $oseverity ? $severity{$i}:$oseverity;
&eventlog(&packevent($i));
}
}
if ($libdebug) {print STDERR "(libdebug) update_event:\n\t";&printevent($i);}
} # end update_event()
##
## eventlog()
# Send the event to NLOG_HOST using UDP.
#
sub eventlog {
local($event) = @_ ;
local($bytesleft);
local($RETRY_REOPEN) = 1*60 ; # try re-opening logging socket every minute
if ($nlogfd < 0)
{
local($lport);
# do not try again until RETRY_REOPEN secs
if ((time - $nlogclosetime) < $RETRY_REOPEN) { return (-1) ; }
## Get local port number
($junk, $junk, $lport) = getservbyname($NLOG_SERVICE, 'udp');
$lport = $NLOG_PORT unless $lport ;
$nlogfd = &newSocket($NLOG_HOST, $lport, 'udp');
if ($nlogfd < 0) {
print STDERR "eventlog- could not connect to $NLOG_HOST\n";
$nlogclosetime = time ; # record time of last attempt
return (-1);
}
select( (select($nlogfd), $| = 1)[0] ); # make socket unbuffered
($libdebug > 0) && print STDERR "(libdebug) eventlog: socket opened\n";
} # end: if(socket not open)
## Here only if socket has been opened and have to write out EVENT.
$bytesleft = length ($event) ;
while ($bytesleft)
{
local($written);
local($offset) = 0;
$written = syswrite($nlogfd, $event, $bytesleft, $offset);
if ($written <= 0)
{
print STDERR ("(libdebug) eventlog syswrite error: $!\n");
close($nlogfd);
$nlogfd = -1; # reset
return(-1);
}
$bytesleft -= $written;
$offset += $written
} # end: while($bytesleft)
}
##
##
# Standard main.. just create subroutines in your new
# nocol monitor and call nocol_main from your monitors main()
# Subroutines needed are:
# readconf - should define @items
# dotest - shout set $status, $value, $maxseverity
# For varying thresholds of severity, you will have to set the values
# of the global variables '$maxseverity' and '$varthres{$index=$item}'
# in your dotest().
#
sub nocol_main {
&nocol_startup;
&readconf;
foreach $item (@items) {
local ($host, $addr, $junk) = split( /\t/, $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
{
&writeevent(OEVENTS, $item);
}
}
close(OEVENTS);
$deltatime = time - $stime; # time to do tests
if ($sleepint > $deltatime) { sleep($sleepint - $deltatime); }
} # end: while(1)
} # end nocol_main()
##
#
##
|