[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() ## # ## |