#!/usr/local/bin/perl5 ######################################################################## ######################################################################## ### ### ### Developed with funding from the Internet2 Middleware Initiative ### ### ### ### ### ### Intellectual Property rights reserved by the author. ### ### Distribution rights reserved by the author. ### ### Copyright (c) 2002, 2003, 2004, 2005 by Brendan Bellina ### ### ### ### This program can be used freely in ### ### institutions of higher learning. ### ### ### ### This program is distributed in the hope that it will be ### ### useful, but WITHOUT ANY WARRANTY; without even the implied ### ### warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ### ### PURPOSE. For further licensing information please see the ### ### accompanying README.Look file in this distrubution. ### ### ### ######################################################################## ######################################################################## # # Name: Look.pl.mozilla # ########################################## # ### Rename to Look.pl prior to use ### # ########################################## # Language: PERL 5.60 with PerLDAP 1.4.1 # Author: Brendan Bellina (bbellina@alumni.nd.edu) # # [The author extends his thanks to Jeremy McCarty, formerly of the # University of Notre Dame for his invaluable assistance and to # Michael Gettes of Duke University (formerly of Georgetown Univ) for his input.] # # This script designed and tested for PERL 5.60 and PerLDAP 1.4.1 # Use Look.pl.perl-ldap to use a version based on perl-ldap rather than PerLDAP # ######################################################################## # # Command line usage: # # Look.pl [-usage] [-debug] [-windows] [-nofile] [-binddn] [-passwd] [-altpref] # # Parameters: # # req # Name val Description # ---------- --- ------------------------------------------ # '-usage' no Displays command line usage rather than executing # '-debug' no If present debug mode is turned on, overrides debug user preference # '-windows' no For Windows environment, bypasses already executing check # '-nofile' no Redirects output to console and prevents output file rolling # '-binddn' yes Bind dn to use when querying for LDAP stats - overrides binddn user pref # '-passwd' yes Password to use when bind dn used - overrides bindpasswd user pref # '-altpref' yes Path and name of an alternate user preferences file to use rather than Look.up # ######################################################################## # # Description: # # LDAP operational Orca "k"ollector - Look # # This script gathers LDAP performance data at periodic intervals and generates a summary # file that is compatible with the open source Orca web graphing product # (). # # The user preferences file for this script should be stored in the same directory as the # script and should be named "Look.up". The -altpref command line option can be used to # override the path and name of the user preference file. # ####### # # Limitations: # - support for iPlanet Directory Server 4 log format (compatible with SunONE 5) and # Sun Directory Server 5.2 default logfile format (sunDS52 mod contributed by Keith Bucher, Univ of Oregon) # ####### # # Making changes: (line numbers shown in comments below are only approximations) # # If you need to add your own log file format, it should be done in the CASE_LOG_TYPE section. # If you would like to share your code please send it to the author and it may be worked into # the next product release. # # If you want to generate different columns then the sections you will need to consider are: # - the log processing (~530) or LDAP processing (~640) sections of the MAIN processing loop # - the calc avg section (~1000) of the MAIN processing loop # - the init_collectionstats subroutine # - the init_on_LDAP_error subroutine if LDAP processing is being used # - the put_log or put_ldap subroutines depending on the data source # - you will also need to configure Orca to graph the new columns (use the -debug and -nofile # command line arguments to test your output before making ORCA config changes) # # If you want to add new command line arguments you should: # - update the usage information and parameters comments at the top of the program # - update the $arg_usage variable content (search for $arg_usage) # - update the @arg_validargs array content (search for @arg_validargs) # - add your argument handling sometime after the end of the command line routine (~300) # ####### # # Feel free to use the decrement_date subroutine and the command line handling routine # (~100-300) in your own scripts, but give appropriate credit to the author who # retains copyright and all ownership rights. # # ######################################################################## # # VERSION HISTORY # # Version Date Name # Description of modifications # ------- -------- ------------ ------------------------------------ # 1.10 2005/05/31 Brendan Bellina # Added Keith Bucher's Sun Directory Server 5.2 default logfile format mod # Updated copyright notice # 1.00 2004/04/30 Brendan Bellina # Updated copyright notices for NMI release # 0.90 2002/10/27 Brendan Bellina # Initial release # # # ######################################################################## # # Load modules # # Load PerLDAP connection module -- available at use Mozilla::LDAP::Conn; # The FileHandle module allows the conversion of a Perl filehandle to a Perl object. use FileHandle; # #################### # # Define constants # my $c_parmfile = 'Look.up'; # User Preferences file for this script. Overload with -altpref cmd line arg. # #################### # # Process command line arguments and argument parameters # Author: Brendan Bellina, September 2002 # # Excluding comments this routine is 50% larger than the Getopt::Std module but is far more capable. Its # capabilities are almost the same as Getopt::Long, but it is only 40% of its size. Unlike the Getopt # modules the @ARGV is not modified or emptied by this routine. # # - arguments are case-insensitive but argument parameters are case-sensitive # - arguments must start with hyphen (-) and no space should be between the hyphen and the argument # - argument parameters must not start with hyphen and can be separated from the argument by space or not # - an argument parameter following an argument block must be separated by a space # - arguments can be specified fully (-usage) or by their initial character (-u) # - each argument must start with a unique letter # - arguments can be in any order, but argument parameters must immediately follow their argument # - multiple single-letter arguments can be in an argument block, so -d -u -h could be written -duh # - if a parameter follows a block of arguments the parameter is assumed to follow the last argument in the block # - if an argument is repeated then the last position is considered the valid position # - if an invalid argument is specified the variable $arg_error will be set to the invalid argument string # - an argument block will be mistaken for an argument if the block matches the spelling of the argument # - an argument + parameter combination will be mistaken for an argument if there is no space between them # and the spelling matches the spelling of an argument # - an argument + parameter combination will be mistaken for an argument block if there is no space between # them and all of the letters in the parameter are valid arguments # - to determine if an argument has been specified check for it (or its single-letter abbrev) (with or without # the leading hyphen) in %arg # - to retrieve the parameter that followed an argument, find the argument (or its single-letter abbrev) # in %arg and then look in @arg_parm for the element one greater than the %arg value. # If the element retrieved is empty then no parameter followed the argument, otherwise the retrieved element # is the parameter. # For example, to determine if -infile was specified and what file name was provided you would code: # if ($arg{'-infile'}) # could also use $arg{'-i'} or $arg{'infile'} or $arg{'i'} # { # $filename = $arg_parm[$arg{'-infile'}+1]; # could also use $arg{'-i'} or $arg{'infile'} or $arg{'i'} # } # # Define all arg variables @arg_validargs=(); # array of valid full-word arguments %arg_list=(); # hash of valid full-word arguments %arg=(); # cross-reference of arguments passed on the command line to position @arg_block=(); # temporary array used when processing argument blocks @arg_parm=(); # array of argument parameters stored by position $arg_usage; # usage text to display when an error occurs or perhaps when -usage is passed $arg_current; $arg_invalid; $arg_match; $arg_letter; $arg_temp; $arg_error; # will hold an invalid argument if passed $j; $k; $m; # loop variables $arg_usage = "Usage: $0 [-usage] [-debug] [-windows] [-nofile] [-binddn] [-passwd] [-altpref]\n"; # List all valid full-word arguments, make sure they are all in lowercase # and none start with the same letter. @arg_validargs = qw/usage debug windows nofile binddn passwd altpref/; foreach $arg_temp (@arg_validargs) { $arg_list{$arg_temp} = 1; } # end foreach $j = 1; # used to index arguments and parameters foreach $arg_current (@ARGV) { $arg_error = '-' if $arg_current eq '-'; # hyphen by itself is invalid last if $arg_error; # is it an argument or an argument parameter? if (length($arg_current) > 1 and substr($arg_current,0,1) eq '-') { # must be an argument or argument block or argument followed by parameter with no space between $arg_current = substr($arg_current,1); # strip off leading hyphen if ($arg_list{lc($arg_current)}) # check if it is in the argument list { # found in the argument list, must be a full word $arg{lc($arg_current)} = $j; # save full argument and position in the argument x-ref $arg{'-' . lc($arg_current)} = $j; # save full argument preceded by hyphen $arg{substr(lc($arg_current),0,1)} = $j; # save abbrev argument and position in the argument x-ref $arg{'-' . substr(lc($arg_current),0,1)} = $j; # save abbrev argument preceded by hyphen $j++; } # end if else # check to see if it is an argument block or argument followed by a parameter { # Loop through the argument and see if every character is itself an argument initial letter $arg_invalid = 0; @arg_block=(); for ($k=0; $k < length($arg_current) and !$arg_invalid; $k++) { $arg_letter = lc(substr($arg_current,$k,1)); $arg_match = 0; for ($m=0; $m <= $#arg_validargs and !$arg_match; $m++) { if ($arg_letter eq substr($arg_validargs[$m],0,1)) { $arg_match = 1; $arg_block[$k] = $arg_validargs[$m]; } # end if } # end for $arg_invalid = !$arg_match; } # end for if (!$arg_invalid) # it must be an argument block, so process each letter { foreach $arg_temp (@arg_block) { $arg{lc($arg_temp)} = $j; # save full argument and position in the argument x-ref $arg{'-' . lc($arg_temp)} = $j; # save full argument preceded by hyphen $arg{substr(lc($arg_temp),0,1)}= $j; # save abbrev argument and position in the arg x-ref $arg{'-' . substr(lc($arg_temp),0,1)} = $j; # save abbrev argument preceded by hyphen $j++; } # end foreach } # end if else # it must be an argument followed by a parameter or something invalid { if ($arg_block[0] ne '') { # first argument was valid, so it must be an argument followed by a parameter # with no intervening space $arg{lc($arg_block[0])} = $j; # save full argument and position in the arg x-ref $arg{'-' . lc($arg_block[0])} = $j; # save full argument preceded by hyphen $arg{substr(lc($arg_block[0]),0,1)}= $j; # save abbrev argument and position in the arg x-ref $arg{'-' . substr(lc($arg_block[0]),0,1)} = $j; # save abbrev argument preceded by hyphen $j++; # store everything but the initial character in original case in arg_parm array $arg_parm[$j++] = substr($arg_current,1); } # end if else # invalid argument { $arg_error = '-' . $arg_current; } # end else } # end else } # end else } # end if else # must be a parameter { $arg_parm[$j++] = $arg_current; } # end else } # end foreach if ($arg_error) { print "Invalid parameter: " . $arg_error . "\n"; die $arg_usage; } # end if die $arg_usage if $arg{'-usage'}; if ($arg{'-debug'}) { foreach $arg_temp (@arg_validargs) { print "arg_validargs: :" . $arg_temp . ":\n"; } # end foreach for $key (keys %arg_list) { print "arg_list key: :$key: Value: :$arg_list{$key}:\n"; } # end for print "ARGV: "; foreach $arg_temp (@ARGV) { print ":$arg_temp: "; } # end foreach print "\n"; for $key (keys %arg) { print "arg key: :$key: Value: :$arg{$key}:\n"; } # end for for ($j=0; $j<=$#arg_parm; $j++) { print "arg_parm($j): :" . $arg_parm[$j] . ":\n"; } # end for print "End of arguments\n"; } # end if #################### End of command line routine ################ # # Determine if alternate user preference file provided on command line # if ($arg{'-altpref'}) { $c_parmfile = $arg_parm[$arg{'-altpref'}+1]; die "Error ($0): Initiation failure. Required value for -altpref argument not specified.\n" if $c_parmfile eq ''; } #################### # # Read script parameter file # my %parm; # initialize to empty open(INFILE, "<$c_parmfile"); while (my $parmline = ) { chomp $parmline; # remove trailing newline if (length($parmline) > 0 and substr($parmline,0,1) ne "\x23") # \x23 is '#' { (my $parmKey,my $parmVal) = split(/\t/,$parmline,2); # split on tab into key & value $parm{$parmKey} = $parmVal; } # end if } # end while close(INFILE); # close parameter file # #################### # # Read system parameter file (if any specified in the local parm file) # if ($parm{'sysparmfile'} ne '') { open(INFILE, "<$parm{'sysparmfile'}"); while (my $parmline = ) { chomp $parmline; # remove trailing newline if (length($parmline) > 0 and substr($parmline,0,1) ne "\x23") # \x23 is '#' { (my $parmKey,my $parmVal) = split(/\t/,$parmline,2); # split on tab into key & value if (not exists($parm{$parmKey})) # allow local parms to override system parms { $parm{$parmKey} = $parmVal; } # end if } # end if } # end while close(INFILE); # close system parameter file } #################### # # Create standard filehandles # $fh = new FileHandle; $fh_out = new FileHandle; #################### # Check for Debugging mode # $parm{'debug'} = 1 if $arg{'-debug'}; if ($parm{'debug'}) { print STDERR "Debugging output enabled\n\n"; # Create a filehandle object for the debug output. $fh_dbg = new FileHandle; } #################### # Verify that if ldapmonitor=Y and ldapmonitorbind=Y then # binddn and passwd are both specified (could be via user preferences or command line arguments) # if (lc($parm{'ldapmonitor'}) eq 'y' and lc($parm{'ldapmonitorbind'}) eq 'y') { $parm{'binddn'} = $arg_parm[$arg{'-binddn'}+1] if $arg{'-binddn'}; $parm{'bindpasswd'} = $arg_parm[$arg{'-passwd'}+1] if $arg{'-passwd'}; if ($parm{'binddn'} eq '') { die "Error ($0): Initiation failure. LDAP process and bind specified but no bind dn provided.\n"; } elsif ($parm{'bindpasswd'} eq '') { die "Error ($0): Initiation failure. LDAP process and bind specified but no bind passwd provided.\n"; } } #################### # Verify that if ldapmonitor=Y and ldapmonitorbind=Y and ldapmonitorSSL=Y then # there is a cert db specified # if (lc($parm{'ldapmonitorSSL'}) eq 'y' and $parm{'SSLcert'} eq '') { die "Error ($0): Initiation failure. LDAP monitor over SSL requested, but no SSLcert specified.\n"; } #################### # # Abend if process is already running - allow bypass using -windows command line argument if (!$arg{'-windows'}) { my $running = 0; open(IN,"$parm{'processcmd'} |") or die "Error ($0): Initiation failure. Cannot determine if already running.\n"; while() { /\b$0\b/o or next; $running++; } # end while close(IN); if ($running > 1) { die "Error ($0): Initiation failure. Already running.\n"; } # end if } # end if #################### # # Check for Nofile mode - redirect output to STDOUT # This causes the program NOT to write a file, but instead to # dump output (and debug lines if debugging) to stdout and bypass # output file . # if ($arg{'-nofile'}) { print STDERR "Output to console enabled\n\n"; $fh_out = STDOUT; # If in debug mode set the debug filehandle to the console also if ($parm{'debug'}) { $fh_dbg = STDOUT; } } if ($parm{'debug'} and (not $arg{'-nofile'})) { open(DBGOUT, ">$parm{'debugfile'}"); $fh_dbg = DBGOUT; # $fh_dbg is now the filehandle for debug statements } if ($parm{'debug'}) { print $fh_dbg "\nSystem Parms:\n"; for my $key1 (sort keys %parm) { print $fh_dbg "Parm $key1 = $parm{$key1}" . "\n"; } } # # ##################### # # initialize process variables # my $current_column = 0; @col_comment=(); @col_data=(); my $columns_out = 0; &init_collectionstats; # variables that get reset after each write to the output file &init_on_LDAP_error; # set variables that need initialized values for LDAP processing ##################### # # Make sure that either log processing or LDAP processing or both are specified # if (lc($parm{'logprocess_flag'}) ne 'y' and lc($parm{'ldapprocess_flag'}) ne 'y') { die "Error ($0): Initiation failure. Must set logprocess_flag or ldapprocess_flag to Y.\n"; } if (not $arg{'-nofile'}) { open(OUTFILE, ">>$parm{'outputfile'}"); # open for append $fh_out = OUTFILE; } my $ldap_then = time; my $ldapavg_then = $ldap_then; my $ldapput_then = $ldap_then; if ($parm{'debug'}) { print $fh_dbg "ldap_then = $ldap_then\n"; print $fh_dbg "ldapavg_then = $ldapavg_then\n"; print $fh_dbg "ldapput_then = $ldapput_then\n"; } if (lc($parm{'logprocess_flag'}) eq 'y') # read stats from LDAP log file { if ($parm{'debug'}) { print $fh_dbg "Initial open of $parm{'ldap_logfile'}\n"; } open(INFILE, "<$parm{'ldap_logfile'}"); $fh = INFILE; ($ino_save,$size_save) = (stat(INFILE))[1,7]; # save inode, and size - stat doesn't work with $fh if ($parm{'debug'}) { print $fh_dbg "ino_save = $ino_save\n"; print $fh_dbg "size_save = $size_save\n"; } seek($fh, 0, 2); # advance the pointer to the end of the log file if ($parm{'debug'}) { print $fh_dbg "Sleep for $parm{'collection_interval'} seconds...\n"; } sleep($parm{'collection_interval'}); # sleep one interval before beginning log review } # The following dates and indicators are used to control rolling the output file over periodically my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); # Reassemble. $year is current year minus 1900. $mon is in the range 0-11. # $date=sprintf("%04d%02d%02d%02d%02d%02d",$year+1900,$mon+1,$mday,$hour,$min,$sec); # YYYYMMDDhhmmss my $current_date_YYYYMMDD = sprintf("%04d%02d%02d",$year+1900,$mon+1,$mday); my $current_time_HHMMSS = sprintf("%02d%02d%02d",$hour,$min,$sec); $parm{'rotate_out_time'} = '23:30' if $parm{'rotate_out_time'} eq ''; # default to 11:30 pm my $roll_time_HHMMSS = substr($parm{'rotate_out_time'},0,2) . substr($parm{'rotate_out_time'},3,2) . '00'; if ($current_time_HHMMSS >= $roll_time_HHMMSS) { # indicate already rolled for today, so that it doesn't roll again $roll_ind = 1; $roll_date = $current_date_YYYYMMDD; } else { # indicate prior roll was yesterday so it can tell if a day is skipped $roll_ind = 0; $roll_date = &decrement_date($current_date_YYYYMMDD); } my $err = 0; MAIN: while (!$err) # MAIN while loop { if ($parm{'debug'}) { print $fh_dbg "Begin MAIN while loop\n"; } if (lc($parm{'logprocess_flag'}) eq 'y') # read stats from ldap log file { if (not $fh) # if logfile not already open { open(INFILE, "<$parm{'ldap_logfile'}"); $fh = INFILE; ($ino_save,$size_save) = (stat(INFILE))[1,7]; # save inode, and size - stat doesn't work with $fh if ($parm{'debug'}) { print $fh_dbg "Opening logfile $parm{'ldap_logfile'}\n"; print $fh_dbg "ino_save = $ino_save\n"; print $fh_dbg "size_save = $size_save\n"; } } # end if $_ = $parm{'logtype'}; # set $_ to the log type parameter for the CASE_LOG_TYPE to use CASE_LOG_TYPE: { /^iDS4$/ && do { # iPlanet Directory Server 4 if ($parm{'debug'}) { print $fh_dbg "Begin log harvest loop for $parm{'logtype'}\n"; } while (my $inline = ) { ($datetime,$timezone,$connection,$fdop,$slottype,$linebody) = split(/ /,$inline,6); $_ = $slottype; # set $_ to the variable for the case statement to use for comparisons CASE_iDS4: { /^slot=/ && do { # connection made ($word,$lineremainder) = split(/ /,$linebody,2); $connops++ if $word eq 'connection'; $SSLconnops++ if $word eq 'SSL'; # SSL connection last CASE_iDS4; }; /^BIND$/ && do { # BIND operation $bindops++; ($word,$lineremainder) = split(/ /,$linebody,2); $anonbindops++ if $word eq 'dn=""'; # anonymous BIND last CASE_iDS4; }; /^SRCH$/ && do { # SRCH operation $srchops++; last CASE_iDS4; }; /^RESULT$/ && do { # Results back, track only BIND and SRCH ($word,$lineremainder) = split(/ /,$linebody,2); if ($word eq 'err=0') # No error in the results { ($word,$lineremainder) = split(/ /,$lineremainder,2); if ($word eq 'tag=101') # SRCH results { ($word,$lineremainder) = split(/ /,$lineremainder,2); if ($word ne 'nentries=0') { $word = substr($word,9); $srchresults += $word; } } # end if } # end if else # Error in the results { ($word,$lineremainder) = split(/ /,$lineremainder,2); if ($word eq 'tag=97') # BIND error { $binderrors++; } # end if elsif ($word eq 'tag=101') # SRCH error { $srcherrors++; ($word,$lineremainder) = split(/ /,$lineremainder,2); if ($word ne 'nentries=0') { $word = substr($word,9); $srchresults += $word; } } # end elsif } # end else last CASE_iDS4; }; } # end CASE_iDS4 } # end while last CASE_LOG_TYPE; }; # end iDS4 do # # UO MOD Keith Bucher -- Added Sun DS 5.2 format. # Contribution by Keith Bucher, University of Oregon, kbucher@uoregon.edu, May 2005 # Further reference can hopefully be found at http://docs.sun.com/source/816-6699-10/logfiles.html#14394 /^sunDS52$/ && do { # Sun Directory Server 5.2 default logfile format if ($parm{'debug'}) { print $fh_dbg "Begin log harvest loop for $parm{'logtype'}\n"; } while (my $inline = ) { ($datetime,$timezone,$connection,$fdop,$messageid,$throwaway,$slottype,$linebody) = split(/ /,$inline,8); $_ = $slottype; # set $_ to the variable for the case statement to use for comparisons CASE_sunDS52: { /^fd=/ && do { # connection made ($slot,$word,$lineremainder) = split(/ /,$linebody,3); # Note -- Slot is not used, it is always the same as fd. # The Sun DS 5.2 reference manual states that it is a legacy item. $connops++ if $word eq 'LDAP'; $SSLconnops++ if $word eq 'LDAPS'; # SSL connection last CASE_sunDS52; }; /^BIND$/ && do { # BIND operation $bindops++; ($word,$lineremainder) = split(/ /,$linebody,2); $anonbindops++ if $word eq 'dn=""'; # anonymous BIND last CASE_sunDS52; }; /^SRCH$/ && do { # SRCH operation $srchops++; last CASE_sunDS52; }; /^RESULT$/ && do { # Results back, track only BIND and SRCH ($word,$lineremainder) = split(/ /,$linebody,2); if ($word eq 'err=0') # No error in the results { ($word,$lineremainder) = split(/ /,$lineremainder,2); if ($word eq 'tag=101') # SRCH results { ($word,$lineremainder) = split(/ /,$lineremainder,2); if ($word ne 'nentries=0') { $word = substr($word,9); $srchresults += $word; } } # end if } # end if else # Error in the results { ($word,$lineremainder) = split(/ /,$lineremainder,2); if ($word eq 'tag=97') # BIND error { $binderrors++; } # end if elsif ($word eq 'tag=101') # SRCH error { $srcherrors++; ($word,$lineremainder) = split(/ /,$lineremainder,2); if ($word ne 'nentries=0') { $word = substr($word,9); $srchresults += $word; } } # end elsif } # end else last CASE_sunDS52; }; } # end CASE_sunDS52 } # end while last CASE_LOG_TYPE; }; # end CASE_sunDS52 do # End UO MOD kbucher # # insert while loop for any additional log file formats here using a similar CASE structure # # invalid or no log file format specified die "Error ($0): Unknown or unspecified log file format type.\n"; } # end CASE_LOG_TYPE # Determine if new log file is available, and if so switch to begin processing it ($ino,$size) = (stat($parm{'ldap_logfile'}))[1,7]; if ($ino ne $ino_save || $size < $size_save) # if new log file available { $fh->close; # close log file $fh = ''; next; # go immediately to top of MAIN while loop } # end if } # end if if (lc($parm{'ldapprocess_flag'}) eq 'y') { # read stats from LDAP directory if (! $ldap_conn) # connect to the LDAP directory if there isn't already an open connection { if (lc($parm{'ldapmonitorbind'}) eq 'y') { if (lc($parm{'ldapmonitorSSL'}) ne 'y') { $ldap_conn = new Mozilla::LDAP::Conn("$parm{'ldaphost'}", "$parm{'ldapport'}", "$parm{'binddn'}", "$parm{'passwd'}"); } else { # use SSL cert $ldap_conn = new Mozilla::LDAP::Conn("$parm{'ldaphost'}", "$parm{'ldapport'}", "$parm{'binddn'}", "$parm{'passwd'}", "$parm{'SSLcert'}"); } } else { $ldap_conn = new Mozilla::LDAP::Conn("$parm{'ldaphost'}", "$parm{'ldapport'}"); } } # end if if ($ldap_conn) { my $scope = 'base'; my $reqfilter = "objectclass=\*"; my $base = $parm{'ldapmonitor'}; # Use the commented out format below if you want to restrict the returned attributes #my @attrList = ('currentconnections', # 'opsinitiated', # 'opscompleted', # 'entriessent', # 'bytessent' # ); # attributes needed #$monitor = $ldap_conn->search("$base", "$scope", "$reqfilter", 0, @attrList); $monitor = $ldap_conn->search("$base", "$scope", "$reqfilter"); if ($errcode = $ldap_conn->getErrorCode()) { if (lc($parm{'ldapprocess_cont'}) ne 'y') { print "Error ($0): perLDAP error - $errcode:\n"; $ldap_conn->printError(); exit(1); # search failed } else { &init_on_LDAP_error; $ldap_conn = ''; $monitor = ''; } } # end if if ($monitor) { $currconn = ($monitor->getValues("currentconnections"))[0]; if ($parm{'debug'}) { print $fh_dbg "currentconnections=$currconn\n"; } $high_conn = $currconn if $currconn > $high_conn; $curr_opsinit = ($monitor->getValues("opsinitiated"))[0]; if ($parm{'debug'}) { print $fh_dbg "opsinitiated=$curr_opsinit\n"; } if ($last_opsinit > -1) { $tmpdelta_opsinit = ($curr_opsinit - $last_opsinit); } else { $tmpdelta_opsinit = 0; } $delta_opsinit += $tmpdelta_opsinit; $high_opsinit = $tmpdelta_opsinit if $tmpdelta_opsinit > $high_opsinit; $last_opsinit = $curr_opsinit; $curr_opscomp = ($monitor->getValues("opscompleted"))[0]; if ($parm{'debug'}) { print $fh_dbg "opscompleted=$curr_opscomp\n"; } if ($last_opscomp > -1) { $tmpdelta_opscomp = ($curr_opscomp - $last_opscomp); } else { $tmpdelta_opscomp = 0; } $delta_opscomp += $tmpdelta_opscomp; $high_opscomp = $tmpdelta_opscomp if $tmpdelta_opscomp > $high_opscomp; $last_opscomp = $curr_opscomp; $curr_entrsent = ($monitor->getValues("entriessent"))[0]; if ($parm{'debug'}) { print $fh_dbg "entriessent=$curr_entrsent\n"; } if ($last_entrsent > -1) { $tmpdelta_entrsent = ($curr_entrsent - $last_entrsent); } else { $tmpdelta_entrsent = 0; } $delta_entrsent += $tmpdelta_entrsent; $high_entrsent = $tmpdelta_entrsent if $tmpdelta_entrsent > $high_entrsent; $last_entrsent = $curr_entrsent; $curr_bytesent = ($monitor->getValues("bytessent"))[0]; if ($parm{'debug'}) { print $fh_dbg "bytessent=$curr_bytesent\n"; } if ($last_bytesent > -1) { $tmpdelta_bytesent = ($curr_bytesent - $last_bytesent); } else { $tmpdelta_bytesent = 0; } $delta_bytesent += $tmpdelta_bytesent; $high_bytesent = $tmpdelta_bytesent if $tmpdelta_bytesent > $high_bytesent; $last_bytesent = $curr_bytesent; if (lc($parm{'ldapmonitorldbm'}) ne '') { my $scope = 'base'; my $reqfilter = "objectclass=\*"; my $base = $parm{'ldapmonitorldbm'}; # Use the commented out format below if you want to restrict the returned attributes #my @attrList = ('entrycachehits', # 'entrycachetries', # 'entrycachehitratio', # 'dbchehits', # 'dbcachetries', # 'dbcachehitratio' # ); # attributes needed #$monitor = $ldap_conn->search("$base", "$scope", "$reqfilter", 0, @attrList); $monitor = $ldap_conn->search("$base", "$scope", "$reqfilter"); if ($errcode = $ldap_conn->getErrorCode()) { if (lc($parm{'ldapprocess_cont'}) ne 'y') { print "Error ($0): perLDAP error - $errcode:\n"; $ldap_conn->printError(); exit(1); # search failed } else { &init_on_LDAP_error; $ldap_conn = ''; $monitor = ''; } } # end if if ($monitor) { $curr_entrycachehits = ($monitor->getValues("entrycachehits"))[0]; if ($parm{'debug'}) { print $fh_dbg "entrycachehits=$curr_entrycachehits\n"; } if ($last_entrycachehits > -1) { $tmpdelta_entrycachehits = ($curr_entrycachehits - $last_entrycachehits); } else { $tmpdelta_entrycachehits = 0; } $delta_entrycachehits += $tmpdelta_entrycachehits; $high_entrycachehits = $tmpdelta_entrycachehits if $tmpdelta_entrycachehits > $high_entrycachehits; $last_entrycachehits = $curr_entrycachehits; $curr_entrycachetries = ($monitor->getValues("entrycachetries"))[0]; if ($parm{'debug'}) { print $fh_dbg "entrycachetries=$curr_entrycachetries\n"; } if ($last_entrycachetries > -1) { $tmpdelta_entrycachetries = ($curr_entrycachetries - $last_entrycachetries); } else { $tmpdelta_entrycachetries = 0; } $delta_entrycachetries += $tmpdelta_entrycachetries; $high_entrycachetries = $tmpdelta_entrycachetries if $tmpdelta_entrycachetries > $high_entrycachetries; $last_entrycachetries = $curr_entrycachetries; $curr_entrycachehitratio = ($monitor->getValues("entrycachehitratio"))[0]; if ($parm{'debug'}) { print $fh_dbg "entrycachehitratio=$curr_entrycachehitratio\n"; } $high_entrycachehitratio = $curr_entrycachehitratio if $curr_entrycachehitratio > $high_entrycachehitratio; $curr_dbchehits = ($monitor->getValues("dbchehits"))[0]; if ($parm{'debug'}) { print $fh_dbg "dbchehits=$curr_dbchehits\n"; } if ($last_dbchehits> -1) { $tmpdelta_dbchehits = ($curr_dbchehits - $last_dbchehits); } else { $tmpdelta_dbchehits = 0; } $delta_dbchehits += $tmpdelta_dbchehits; $high_dbchehits = $tmpdelta_dbchehits if $tmpdelta_dbchehits > $high_dbchehits; $last_dbchehits = $curr_dbchehits; $curr_dbcachetries = ($monitor->getValues("dbcachetries"))[0]; if ($parm{'debug'}) { print $fh_dbg "dbcachetries=$curr_dbcachetries\n"; } if ($last_dbcachetries > -1) { $tmpdelta_dbcachetries = ($curr_dbcachetries - $last_dbcachetries); } else { $tmpdelta_dbcachetries = 0; } $delta_dbcachetries += $tmpdelta_dbcachetries; $high_dbcachetries = $tmpdelta_dbcachetries if $tmpdelta_dbcachetries > $high_dbcachetries; $last_dbcachetries = $curr_dbcachetries; $curr_dbcachehitratio = ($monitor->getValues("dbcachehitratio"))[0]; if ($parm{'debug'}) { print $fh_dbg "dbcachehitratio=$curr_dbcachehitratio\n"; } $high_dbcachehitratio = $curr_dbcachehitratio if $curr_dbcachehitratio > $high_dbcachehitratio; } # end if $monitor (for ldapmonitorldbm) } # end if $parm{'ldapmonitorldbm'} ne '' } # end if $monitor (for ldapmonitor) } # end if $ldap_conn else { if (lc($parm{'ldapprocess_cont'}) eq 'y') { &init_on_LDAP_error; } else { die "Error ($0): Unable to connect to LDAP server $parm{'ldaphost'}.\n"; } } } # end of LDAP processing if (lc($parm{'calcavgpeak_flag'}) eq 'y') { $ldapavg_now = time; $ldapavg_interval = $ldapavg_now - $ldapavg_then; $ldapavg_then = $ldapavg_now; if (lc($parm{'logprocess_flag'}) eq 'y') # calc avg stats from ldap log file data { $ltmp = ($connops - $lastconnops)/$ldapavg_interval; $connopsavg = $ltmp if $ltmp > $connopsavg; $lastconnops = $connops; $ltmp = ($SSLconnops - $lastSSLconnops)/$ldapavg_interval; $SSLconnopsavg = $ltmp if $ltmp > $SSLconnopsavg; $lastSSLconnops = $connops; $ltmp = ($bindops - $lastbindops)/$ldapavg_interval; $bindopsavg = $ltmp if $ltmp > $bindopsavg; $lastbindops = $bindops; $ltmp = ($anonbindops - $lastanonbindops)/$ldapavg_interval; $anonbindopsavg = $ltmp if $ltmp > $anonbindopsavg; $lastanonbindops = $anonbindops; $ltmp = ($binderrors - $lastbinderrors)/$ldapavg_interval; $binderrorsavg = $ltmp if $ltmp > $binderrorsavg; $lastbinderrors = $binderrors; $ltmp = ($srchops - $lastsrchops)/$ldapavg_interval; $srchopsavg = $ltmp if $ltmp > $srchopsavg; $lastsrchops = $srchops; $ltmp = ($srcherrors - $lastsrcherrors)/$ldapavg_interval; $srcherrorsavg = $ltmp if $ltmp > $srcherrorsavg; $lastsrcherrors = $srcherrors; $ltmp = ($srchresults - $lastsrchresults)/$ldapavg_interval; $srchresultsavg = $ltmp if $ltmp > $srchresultsavg; $lastsrchresults = $srchresults; } # end if if (lc($parm{'ldapprocess_flag'}) eq 'y') # calc avg stats from ldap data { ########################################## ### Insert ldap monitor avg calcs here ### ########################################## } # end if } # end if $collection_counter++; # append stats to output file if ($collection_counter == $parm{'collections_per_write'}) { $ldapput_now = time; $ldap_interval = $ldapput_now - $ldapput_then; $ldapput_then = $ldapput_now; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($ldapput_now); # Reassemble. $year is current year minus 1900. $mon is in the range 0-11. # $date=sprintf("%04d%02d%02d%02d%02d%02d",$year+1900,$mon+1,$mday,$hour,$min,$sec); # YYYYMMDDhhmmss $locltime = sprintf("%02d:%02d:%02d",$hour,$min,$sec); &put_headercolumns; &put_log if lc($parm{'logprocess_flag'}) eq 'y'; &put_ldap if lc($parm{'ldapprocess_flag'}) eq 'y'; &write_output; &init_collectionstats; } # end if if (not $arg{'-nofile'}) # if writing to an output file check for rollover { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); # Reassemble. $year is current year minus 1900. $mon is in the range 0-11. $current_date_YYYYMMDD = sprintf("%04d%02d%02d",$year+1900,$mon+1,$mday); $current_datetime=sprintf("%04d%02d%02d%02d%02d%02d",$year+1900,$mon+1,$mday,$hour,$min,$sec); # YYYYMMDDhhmmss $current_time_HHMMSS = sprintf("%02d%02d%02d",$hour,$min,$sec); if ($current_time_HHMMSS >= $roll_time_HHMMSS and $roll_ind == 0) { # time to roll the output file over if ($parm{'debug'}) { print $fh_dbg "Time to roll the output file over\n"; } &roll_outfile; } elsif ($current_time_HHMMSS < $roll_time_HHMMSS and $roll_ind == 0 and &decrement_date($current_date_YYYYMMDD) > $roll_date) { # skipped past a day, roll over for yesterday if ($parm{'debug'}) { print $fh_dbg "Skipped past a day, roll over for yesterday\n"; } &roll_outfile; $roll_date = &decrement_date($current_date_YYYYMMDD); } if ($current_time_HHMMSS < $roll_time_HHMMSS and $current_date_YYYYMMDD > $roll_date and $roll_ind) { if ($parm{'debug'}) { print $fh_dbg "Reset roll indicator to 0\n"; } $roll_ind = 0; # reset the roll indicator since it is a new day } if ($current_time_HHMMSS >= $roll_time_HHMMSS and $roll_ind == 1 and $current_date_YYYYMMDD > $roll_date) { # went past time to roll without resetting the roll indicator if ($parm{'debug'}) { print $fh_dbg "Went past time to roll over without resetting the roll indicator\n"; } &roll_outfile; } } sleep($parm{'collection_interval'}); } # end MAIN while loop #################### # # Subroutines # #################### sub init_collectionstats { # initialize collection statistics $collection_counter = 0; $connops = 0; $connopsavg = 0; $SSLconnops = 0; $SSLconnopsavg = 0; $bindops = 0; $bindopsavg = 0; $anonbindops = 0; $anonbindopsavg = 0; $binderrors = 0; $binderrorsavg = 0; $srchops = 0; $srchopsavg = 0; $srcherrors = 0; $srcherrorsavg = 0; $srchresults = 0; $srchresultsavg = 0; $lastconnops = 0; $lastSSLconnops = 0; $lastbindops = 0; $lastanonbindops = 0; $lastbinderrors = 0; $lastsrchops = 0; $lastsrcherrors = 0; $lastsrchresults = 0; $currconn = 0; $high_conn = 0; $curr_opsinit = 0; $delta_opsinit = 0; $high_opsinit = 0; $curr_opscomp = 0; $delta_opscomp = 0; $high_opscomp = 0; $curr_entrsent = 0; $delta_entrsent = 0; $high_entrsent = 0; $curr_bytesent = 0; $delta_bytesent = 0; $high_bytesent = 0; $curr_entrycachehits = 0; $delta_entrycachehits = 0; $high_entrycachehits = 0; $curr_entrycachetries = 0; $delta_entrycachetries = 0; $high_entrycachetries = 0; $curr_entrycachehitratio = 0; $high_entrycachehitratio = 0; $curr_dbchehits = 0; $delta_dbchehits = 0; $high_dbchehits = 0; $curr_dbcachetries = 0; $delta_dbcachetries = 0; $high_dbcachetries = 0; $curr_dbcachehitratio = 0; $high_dbcachehitratio = 0; } # sub init_collectionstats #################### sub init_on_LDAP_error { # set anything that needs to be in the event of an LDAP error # generally these are the attributes that you want to graph period deltas rather than # the actual values $last_opsinit = -1; $last_opscomp = -1; $last_entrsent = -1; $last_bytesent = -1; $last_entrycachehits = -1; $last_entrycachetries = -1; $last_dbchehits = -1; $last_dbcachetries = -1; } # sub init_on_LDAP_error #################### sub put_output { # add a column of data to the output buffer my ($comment, $data) = @_; $col_comment[$current_column] = $comment; $col_data[$current_column] = $data; $current_column++; } # sub put_output #################### sub put_headercolumns { # Initial columns that ORCA expects &put_output(" timestamp", sprintf("%10d", $ldapput_now)); &put_output("locltime", $locltime); } # sub put_headercolumns #################### sub put_log { &put_output("connops/s", sprintf("%8.2f", $connops/$ldap_interval)); &put_output("connops/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $connopsavg)) if lc($parm{'calcavgpeak_flag'}) eq 'y'; &put_output("SSLconnops/s", sprintf("%8.2f", $SSLconnops/$ldap_interval)); &put_output("SSLconnops/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $SSLconnopsavg)) if lc($parm{'calcavgpeak_flag'}) eq 'y'; &put_output("bindops/s", sprintf("%8.2f", $bindops/$ldap_interval)); &put_output("bindops/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $bindopsavg)) if lc($parm{'calcavgpeak_flag'}) eq 'y'; &put_output("anonbindops/s", sprintf("%8.2f", $anonbindops/$ldap_interval)); &put_output("anonbindops/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $anonbindopsavg)) if lc($parm{'calcavgpeak_flag'}) eq 'y'; &put_output("binderrors/s", sprintf("%8.2f", $binderrors/$ldap_interval)); &put_output("binderrors/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $binderrorsavg)) if lc($parm{'calcavgpeak_flag'}) eq 'y'; &put_output("srchops/s", sprintf("%8.2f", $srchops/$ldap_interval)); &put_output("srchops/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $srchopsavg)) if lc($parm{'calcavgpeak_flag'}) eq 'y'; &put_output("srcherrors/s", sprintf("%8.2f", $srcherrors/$ldap_interval)); &put_output("srcherrors/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $srcherrorsavg)) if lc($parm{'calcavgpeak_flag'}) eq 'y'; &put_output("srchresults/s", sprintf("%8.2f", $srchresults/$ldap_interval)); &put_output("srchresults/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $srchresultsavg)) if lc($parm{'calcavgpeak_flag'}) eq 'y'; } # sub put_log #################### sub put_ldap { &put_output("conn", sprintf("%8.2f", $currconn)); &put_output("conn/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $high_conn)); &put_output("d_opsinit", sprintf("%8.2f", $delta_opsinit)); &put_output("d_opsinit/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $high_opsinit)); &put_output("d_opscomp", sprintf("%8.2f", $delta_opscomp)); &put_output("d_opscomp/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $high_opscomp)); &put_output("d_entrsent", sprintf("%8.2f", $delta_entrsent)); &put_output("d_entrsent/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $high_entrsent)); &put_output("d_bytesent", sprintf("%8.2f", $delta_bytesent)); &put_output("d_bytesent/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $high_bytesent)); &put_output("d_entrchits", sprintf("%8.2f", $delta_entrycachehits)); &put_output("d_entrchits/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $high_entrycachehits)); &put_output("d_entrctries", sprintf("%8.2f", $delta_entrycachetries)); &put_output("d_entrctries/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $high_entrycachetries)); &put_output("chitratio", sprintf("%8.2f", $curr_entrycachehitratio)); &put_output("chitratio/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $high_entrycachehitratio)); &put_output("d_entrdbchits", sprintf("%8.2f", $delta_dbchehits)); &put_output("d_entrdbchits/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $high_dbchehits)); &put_output("d_entrdbctries", sprintf("%8.2f", $delta_dbcachetries)); &put_output("d_entrdbctries/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $high_dbcachetries)); &put_output("dbchitratio", sprintf("%8.2f", $curr_dbcachehitratio)); &put_output("dbchitratio/p".$parm{'collection_interval'}."s", sprintf("%8.2f", $high_dbcachehitratio)); } # sub put_ldap #################### sub write_output { if ($parm{'debug'}) { print $fh_dbg "write_output\n"; } if ($columns_out == 0) { # if no columns then output col_comment[]\n if ($parm{'debug'}) { print $fh_dbg "write columns headers\n"; } my $templine = ''; foreach (@col_comment) { $templine .= $_ . ' '; } # end foreach $templine =~ s/ $/\n/; # swap last space for newline print $fh_out $templine; if ($parm{'debug'} and not $arg{'-nofile'}) { print $fh_dbg "line written = $templine"; } $columns_out = 1; } # end if my $templine = ''; foreach (@col_data) { $templine .= $_ . ' '; } # end foreach $templine =~ s/ $/\n/; # swap last space for newline print $fh_out $templine; if ($parm{'debug'} and not $arg{'-nofile'}) { print $fh_dbg "line written = $templine"; } $fh_out->flush(); # flush the output buffer if ($parm{'debug'}) { for ($i=0; $i <= $#col_data; $i++) { print "col_data($i):$col_comment[$i]:" . $col_data[$i] . ":\n"; } } if ($parm{'debug'}) { print $fh_dbg "Clear output arrays\n"; } @col_comment=(); @col_data=(); $current_column = 0; } # sub write_output #################### sub roll_outfile { if ($parm{'debug'}) { print $fh_dbg "roll_outfile routine\n"; } # close current output file $fh_out->close(); # rename current output file by appending the datetime stamp my @renamecmd = ( 'mv', $parm{'outputfile'}, $parm{'outputfile'}.'.'.$current_datetime); if ( !(open(RENAME, "-|") || exec @renamecmd)) { die "Error ($0): Unable to roll over output file at $current_datetime\n"; } close(RENAME); # open new output file open(OUTFILE, ">>$parm{'outputfile'}"); # open for append $fh_out = OUTFILE; $columns_out = 0; # reset to force column titles on new output file $roll_ind = 1; $roll_date = $current_date_YYYYMMDD; } # sub roll_outfile #################### sub decrement_date { # This routine decrements a date, assuming that it comes in in format YYYYMMDD, # and returns the date in the format YYYYMMDD. # This routine adjusts for Leap Years properly. # Author: Brendan Bellina 10/2002 my $indate = @_; my $dd = substr($indate,6,2); my $mm = substr($indate,4,2); my $yyyy = substr($indate,0,4); $dd--; if ($dd == 0) { $mm--; if ($mm == 0) { $mm = 12; $yyyy--; } if ($mm == 4 or $mm == 6 or $mm == 9 or $mm == 11) # handle all 30-day months { $dd = 30; } elsif ($mm == 2) # handle February { $dd = 28 + (($yyyy % 4 == 0) - ($yyyy % 100 == 0) + ($yyyy % 400 == 0)); # adjust for leap years } else # handle all other months (they all have 31 days) { $dd = 31; } } return sprintf("%04d%02d%02d",$yyyy,$mm,$dd); } # sub decrement_date