jablonka.czprosek.czf

hotsanic

Subversion Repositories:
[/] [branches/] [HotSaNIC-0.5.0-pre6/] [rrdtimer.pl] - Rev 36 Go to most recent revision

Compare with Previous - Blame - Download


#!/usr/bin/env perl

# $Id: rrdtimer.pl,v 1.17 2004/07/11 22:39:38 bernisys Exp $

# include PERL libraries
use strict;
use warnings;
use diagnostics;

use FindBin;
use lib $FindBin::RealBin;
# use Getopt::Long;

# include HotSaNIC libraries
use lib "./lib";
use HotSaNICparser;
use HotSaNIClog;

# let all outputs be flushed directly
$|=1;

# set commandline correctly
$0="rrdtimer";
HotSaNIClog::set_modulename("rrdtimer");

(my $CALLDIR=$FindBin::RealBin) =~ s/\/rrdtimer//g;
(my $VERSION = '$Revision: 1.17 $') =~ s/.*(\d+\.\d+).*/$1/;
(my $IDENTIFIER = '$Id: rrdtimer.pl,v 1.17 2004/07/11 22:39:38 bernisys Exp $') =~ s/.*,v (.*) \$/$1/;

HotSaNIClog::info("reading & checking config ($CALLDIR/settings) ...");
my %CONFIG=HotSaNICparser::get_config($CALLDIR);
$CONFIG{MODULEDIR}=$CONFIG{DAEMONDIR}."/modules";
$CONFIG{SCHEDULED}=1;
HotSaNIClog::set_timestamping($CONFIG{TIMESTAMPING});

my ($debuglevel,$runmode)=check_for_args(@ARGV);
$CONFIG{DEBUGLEVEL}=HotSaNIClog::get_debuglevel($CONFIG{DEBUGLEVEL});
$CONFIG{DEBUGLEVEL} |= $debuglevel;
HotSaNIClog::set_debuglevel($CONFIG{DEBUGLEVEL});

if (HotSaNIClog::check_debuglevel("MAIN_CONFIG")) { foreach my $k (keys %CONFIG) { HotSaNIClog::info("configuration -> $k=$CONFIG{$k}"); }}
if ($runmode < 128) { exit 0; }

my $PID=HotSaNICparser::get_pid($CONFIG{PIDFILE},"rrdtimer");
if ( $PID>0 ) {
  HotSaNIClog::error("Another process is running on PID $PID - daemon stopped.");
  exit 1;
  }

my $debug="";
if (($runmode&1)>0) {
  HotSaNIClog::info("Debug mode enabled!");
  HotSaNIClog::info("Identifier: $IDENTIFIER");
  HotSaNIClog::info("Logdir: $CONFIG{LOGDIR}");
  HotSaNIClog::info("PID-file: $CONFIG{PIDFILE}");
  $debug="d";
  }

my @PIDs=();

daemonize();

$SIG{TERM} = \&signalhandler;
$SIG{HUP} = \&signalhandler;
$SIG{USR1} = \&signalhandler;
$SIG{USR2} = \&signalhandler;

main_loop();


######################################################################
#                                                                    #
#  SUBROUTINES BEGIN HERE                                            #
#                                                                    #
######################################################################


######################################################################
#
# signal-handler
#  TERM -> terminate daemon and modules
#  HUP  -> re-configure
#  USR1 -> kill daemon only
#  USR2 -> kill modules only
#
sub signalhandler {
  my ($sig)=@_;

  HotSaNIClog::info("$sig received.");
  if (defined $sig) {
    if (($sig eq "TERM") || ($sig eq "USR2")) {
      HotSaNIClog::info("Stopping all running modules.");
      if (@PIDs) { kill "TERM", @PIDs; @PIDs=(); }
      }

    if (($sig eq "TERM") || ($sig eq "USR1")) {
      HotSaNIClog::info("Daemon exiting normally.");
      if (-e $CONFIG{PIDFILE}) {
        unlink $CONFIG{PIDFILE};
        HotSaNIClog::info("PID-file removed.");
        }
      close STDIN;
      close STDOUT;
      close STDERR;
      exit 0;
      }

    if ($sig eq "HUP") {
            HotSaNIClog::info("reconfiguring myself...");
      %CONFIG=HotSaNICparser::get_config($CALLDIR);
      $CONFIG{MODULEDIR}=$CONFIG{DAEMONDIR}."/modules";
      $CONFIG{SCHEDULED}=1;
      # TODO:
      #
      #  - kill unused modules
      #  - start configured modules (if necessary)
      #  - re-configure all modules
      #
      }
    }
  }


######################################################################
#
# the main loop executes all timed scripts:
#
# signal modules/*/read-data every 10 sec. (hardcoded)
# modules/*/diagrams every $DTIME
# convert() every $CTIME if $CONVERTMETHOD is other than "HTML"
# scan_for_modules() every $STIME
#
sub main_loop {
  my @modules=();
  my %MODULES=();

  my $now=time;
  my $lastscan=0;          # scan for modules directly after being started
  my $lastdiagram=$now-$CONFIG{DTIME}+30; # generate all diagrams 30 sec. after start
  my $lastconvert=$now-$CONFIG{CTIME}+300; # build thumbnails 5 minutes after start

  call_script($CONFIG{DAEMONDIR},"makeindex.pl",0,$CONFIG{LOGDIR}."/makeindex.log",0);

  while () {
    $now=time;

# BUG:  sometimes after HUP'ing the @PIDs array contains undefined values

    if (HotSaNIClog::check_debuglevel("MAIN_HEARTBEAT")) { HotSaNIClog::info("main loop running"); }

    # Tell modules to sample data. We do this BEFORE starting any module to avoid
    # too small sample intervals. At start time @PIDs is empty so this code won't
    # be executed until some modules are started.
    #
    if (@PIDs) {
      if (HotSaNIClog::check_debuglevel("MAIN_SIGNAL")) { HotSaNIClog::info("signaling PIDs: ".join(" ",@PIDs)); }

      # When no schedule time was configured, signal ALL modules in PARALLEL (may produce high load!)
      # Otherwhise serialize the signalling a bit.
      #
      if ($CONFIG{SCHEDULED} == 0) { kill "SIGUSR1", @PIDs; }
      else {
        foreach (@PIDs) {
          if (defined $_) {
            kill "SIGUSR1", $_;
            my $wait=int($CONFIG{SCHEDULE_MIN}+rand($CONFIG{SCHEDULE_MAX}-$CONFIG{SCHEDULE_MIN}))/1000;
            if (HotSaNIClog::check_debuglevel("MAIN_SIGNAL_VERBOSE")) { HotSaNIClog::info("\"$MODULES{$_}\" called, sleeping $wait sec."); }
            select(undef,undef,undef,$wait);
            }
          }
        }
      }
  
    # scan for modules and (re-)start them if necessary
    #
    if ($lastscan+$CONFIG{STIME} <= $now) {
      @modules=HotSaNICparser::scan_for_modules($CONFIG{MODULEDIR},$CONFIG{RUN});
      %MODULES=call_modules(@modules);
      @PIDs=keys(%MODULES);
      $lastscan=int($now/$CONFIG{STIME})*$CONFIG{STIME};
      if ($debug ne "d") { logrotate(); }
      }

    # check if diagrams have to be built.
    #
    if ($lastdiagram+$CONFIG{DTIME} <= $now) {
      my $append;
      if ($CONFIG{DIAGRAMLOG} eq "all") { $append=1; }
      call_script($CONFIG{DAEMONDIR},"diagrams.pl",5,$CONFIG{LOGDIR}."/diagram.log",$append);
      $lastdiagram=int($now/$CONFIG{DTIME})*$CONFIG{DTIME};
      }

    # check if thumbnails have to be generated.
    #
    if (($lastconvert+$CONFIG{CTIME} <= $now) && ($CONFIG{CONVERTMETHOD} ne "HTML")) { 
      call_script($CONFIG{DAEMONDIR},"convert.pl",0,$CONFIG{LOGDIR}."/convert.log",0);
      $lastconvert=int($now/$CONFIG{CTIME})*$CONFIG{CTIME};
      }

    # sleep until system time's next full 10 seconds
    #
    my $sleeptime=10-(time % 10);
    sleep $sleeptime;
    }
  }


######################################################################
#
# start read-data.pl script in each module
#
sub call_modules {
  my (@modules)=@_;
  my %MODULES;
  my $nicelevel="0";
  my $have_started=0;

  if (HotSaNIClog::check_debuglevel("MAIN_SCAN_MODULES")) { HotSaNIClog::info("Checking modules..."); }

  # iterate through all configured modules...
  #
  for my $module (@modules) {
    my $verbose=0;
    if (HotSaNIClog::check_debuglevel("MAIN_SCAN_MODULES_VERBOSE")) { $verbose=1; }
    chdir $CONFIG{MODULEDIR}."/$module";

    my $PID=HotSaNICparser::get_pid();

    # if not running, start the module and wait for PID-file to be generated
    #
    if ($PID == 0) {
      if (HotSaNIClog::check_debuglevel("MAIN_SCAN_MODULES")) { HotSaNIClog::info("starting module \"$module\""); }
      if (HotSaNIClog::check_debuglevel("MAIN_SCAN_MODULES_VERBOSE")) { HotSaNIClog::info("----- begin start module \"$module\" -----"); }
      $verbose=1;
      if (-e "./running.pid") {
        if (HotSaNIClog::check_debuglevel("MAIN_SCAN_MODULES_VERBOSE")) { HotSaNIClog::info("removing old PID-file"); }
        unlink "./running.pid";
        }
      my $EXEC="";
      if (-e "./read-data-wrapper.pl") { $EXEC="nice -$nicelevel ./read-data-wrapper.pl start $module"; }
      elsif (-e "./read-data.pl") { $EXEC="nice -$nicelevel ./read-data.pl start $module"; }
      else {
        HotSaNIClog::error("cannot find read-data script for module \"$module\"");
        next;
        }
      system "$EXEC";

      # wait for module writing its PID-file
      #
      my $count=0;
      while ( ($count<80) && (! -s "./running.pid") ) {
        if ($count == 0) { HotSaNIClog::info("waiting for module's PID-file"); }
        $count++;
        print "." if ($count%5 == 0);
        select(undef,undef,undef,0.25);
        }
      print "\r" if ($count > 0);
      $PID=HotSaNICparser::get_pid();
      #if PID is valid -> sample for the first time after startup
      if ($PID > 0) { kill "SIGUSR1",$PID; }
      HotSaNIClog::info("----- end start module \"$module\" -----"); 
      $have_started++;
      }

    if ($PID >0) {
      if ($verbose>0) { HotSaNIClog::info("\"$module\" running on PID $PID"); }
      $MODULES{$PID}=$module;
      }
    else { HotSaNIClog::error("PID for \"$module\" could not be determined"); }
    }
  if ($have_started>0) { HotSaNIClog::info("-" x 75); }
  return %MODULES;
  }


######################################################################
#
# call external script (incl. sanity checking etc)
#
sub call_script {
  my ($path,$script,$nicelevel,$output,$append)=@_;

  if (! defined $append) { $append=0; }
  if (! defined $output) { $output=""; }
  if (! defined $nicelevel) { $nicelevel=0; }

  if ( (defined $path) && (defined $script) ) {
    if (HotSaNIClog::check_debuglevel("MAIN_CALL_SCRIPT")) { HotSaNIClog::info("executing \"$path/$script\" with nice $nicelevel"); }
    if ( -e "$path/$script") {
      if ($output ne "") {
        my $logaction="appending";
        if (index("1 yes true",lc $append) < 0) {
          rename $output,"$output.old";
          $logaction="logging"; 
          }
        if (HotSaNIClog::check_debuglevel("MAIN_CALL_SCRIPT")) { HotSaNIClog::info("$logaction output to $output"); }
        if ($nicelevel ne 0) {system ("cd \"$path\"; nice -$nicelevel ./$script >$output 2>&1 &"); }
        else {system ("cd \"$path\"; ./$script >$output 2>&1 &"); }
        }
      else {
        if ($nicelevel ne 0) {system ("cd \"$path\"; nice -$nicelevel ./$script &"); }
        else {system ("cd \"$path\"; ./$script &"); }
        }
      }
    else { HotSaNIClog::error("script \"$path/$script\" not found! Check your installation."); }
    }
  }


######################################################################
#
# fork into background
#
sub daemonize {
  use POSIX qw(setsid);
  HotSaNIClog::info("entering daemon mode...");
  if ($debug eq "") {
    close STDIN;
    close STDOUT;
    close STDERR;
    if (open(DEVTTY, "/dev/tty")) { ioctl(DEVTTY,0x20007471,0); close DEVTTY; }
    open STDIN,"/dev/null";
    open STDOUT,">>".$CONFIG{LOGDIR}."/HotSaNIC.log";
    open STDERR,">&STDOUT";
    setpgrp(0,$$);
    chdir "/";
    fork && exit 0;
    setsid;
    HotSaNIClog::info("archiver successfully forked into background and running on PID $$");
    }
  else { HotSaNIClog::info("archiver running in debug-mode on PID $$"); }
  HotSaNIClog::info("-" x 75);
  open FILE,">".$CONFIG{PIDFILE};
  print FILE $$;
  close FILE;
  }


######################################################################
#
# rotate logfiles
#
sub logrotate {
  my ($size,$file);

  if ($debug ne "d") {

    $file=$CONFIG{LOGDIR}."/HotSaNIC.log";
    (undef,undef,undef,undef,undef,undef,undef,$size,undef,undef,undef,undef,undef) = stat($file);
    if (defined $size) {
      if ($size > $CONFIG{LOGSIZE}) {
        HotSaNIClog::info("$file exceeding $CONFIG{LOGSIZE} bytes - rotating - keeping $CONFIG{LOGBACKUPS} backups.");
        for (my $nn=$CONFIG{LOGBACKUPS};$nn>1;$nn--) {
          if ( -e "$file.$nn" ) { unlink "$file.$nn"; }
          if ( -e "$file.".($nn-1) ) { rename "$file.".($nn-1),"$file.".$nn; }
          }
        close STDOUT;
        rename $file,"$file.1";
        open STDOUT,">>$file";
        close STDERR;
        rename $file,"$file.1";
        open STDERR,">>$file";
        }
      }
    }
  }


######################################################################
#
# evaluate commandline arguments
#
sub check_for_args {
  HotSaNIClog::info("evaluating cmdline arguments...");
  my @args=@_;

  # set initial values
  #
  my $debuglevel=0;
  my $runmode=0;

  # Check if we were called with any options
  #
  foreach my $arg (@args) {
    if (index($arg,"d") >= 0) { $runmode|=1; }
    if (index($arg,"D") >= 0) { $runmode|=128; }
    if (index($arg,"h") >= 0) { $runmode|=256; }
    if (index($arg,"?") >= 0) { $runmode|=256; }
    $arg=~ s/[a-zA-Z]//g;
    if ($arg =~ /[0-9]/) { if ($arg > 0) { $debuglevel=$arg; } }
    }
  
  if (($runmode == 0) || ($runmode > 255)) {
    print "rrdtimer - CVS version $VERSION ($IDENTIFIER) - OS: $^O\n";
    print "usage:\nrrdtimer [options[debuglevel]]\n  options:\n";
    print "  D - enter daemon-mode (i.e. start the main loop)\n";
    print "  d - enter debugging mode (don't fork into background)\n";
    print "\n";
    exit 0;
    }
  return ($debuglevel,$runmode);
  }



Powered by WebSVN 2.2.1