![]() ![]() |
hotsanic |
Subversion Repositories: |
Compare with Previous - Blame - Download
## $Id: HotSaNICmod.pm,v 1.42 2004/08/30 11:21:22 bernisys Exp $#package HotSaNICmod;use HotSaNICparser;use HotSaNIClog;use RRDs;my $MODNAME;my %MODARGS;my %CONFglob;my $SAMPLING=0;my $SAMPLE_LAST=0;my $SAMPLE_DURATION=0;($VERSION = '$Revision: 1.42 $') =~ s/.*(\d+\.\d+).*/$1/;######################################################################## control function to make sure that a module is running only once## Usage:# dupe_control($what,@messages);## $what:# start -> call this method at the head of a module to touch the# dupe-detection checkfile.# stop -> remove PIDfile and exit normally.# die -> stop process with error.# warn -> print $message as warning and continue execution.# FOR COMPATIBILITY REASONS ONLY!# please use HotSaNIClog::warn# info -> print $message and continue execution.# FOR COMPATIBILITY REASONS ONLY!# please use HotSaNIClog::info## each message will be preceded with a timestamp and the module name#sub dupe_control {my $what=shift;my $pid=0;my $delta=0;my $line;if ( ($what eq "check") || ($what eq "start") ) { $pid=HotSaNICparser::get_pid(); }if ($what eq "info") {HotSaNIClog::error("HotSaNICmod::dupe_control(\"info\",...); is deprecated, use HotSaNIClog::info instead!");HotSaNIClog::info(@_);}elsif ($what eq "warn") {HotSaNIClog::error("HotSaNICmod::dupe_control(\"warn\",...); is deprecated, use HotSaNIClog::warn instead!");HotSaNIClog::warn(@_);}elsif ($what eq "start") {if ($pid > 0) {HotSaNIClog::error("process already running on PID $pid for $delta seconds.");exit 1;}open FILE,">running.pid";print FILE $$;close FILE;HotSaNIClog::info("process forked to background.");}elsif ($what eq "stop") {HotSaNIClog::info("exiting normally.");if (-e "running.pid") { unlink "running.pid"; }exit 0;}elsif ($what eq "die") {HotSaNIClog::error(@_);exit 1;}elsif ($what eq "check") {if (!defined $pid) { $pid=0; }if (($pid > 0) && (-e "/proc/$pid/stat")) {open FILE,"/proc/$pid/stat";@fileds=split / /,<FILE>;close FILE;$starttime=$fileds[21]/100;open FILE,"/proc/uptime";$line=<FILE>;close FILE;($uptime)=split / /,$line;$delta=int(($uptime-$starttime)*100)/100;}if (($pid > 0) && ($^O =~ /bsd/)) {open FILE,"/proc/$pid/status";@fileds=split / /,<FILE>;close FILE;($starttime, $msec)= split /,/, $fileds[7];$delta=int((time-$starttime)*100)/100;}if (!defined $delta) { $delta=0; }return ($pid,$delta);}else { HotSaNIClog::error("HotSaNICmod::dupe_control method \"$what\" not supported."); }}######################################################################## check cmdline arguments#sub init {$args=shift || "";$MODNAME=HotSaNICparser::get_module_name();%CONFglob=HotSaNICparser::get_config("../..",$MODNAME);if (scalar(keys(%CONFglob)) == 0) { HotSaNICmod::dupe_control("die","missing global settings file"); }HotSaNIClog::set_timestamping($CONFglob{TIMESTAMPING});my $found=0;my @possible_args=("nodaemon","start","stop","status","configure","sample","update","version","help","showargs");foreach (@possible_args) { if ($args eq $_) { $found++; } }if ($found == 0) { $args=""; }if ( $args eq "" ) {print "usage: $0 [".join("/",@possible_args)."]\n";print "\n";exit 1;}if ( $args =~ /help/) {print "usage: $0 [".join("/",@possible_args)."]\n";print "\n";print "alternative usage: send a signal to <module PID>\n";print "\n";print "argument signal function\n";print "--------- ------- --------------------------------------------------\n";print "nodaemon start module in foreground\n";print "start start module daemon\n";print "stop SIGTERM terminate module daemon\n";print "status show status of module daemon\n";print "configure SIGHUP daemon re-reads its config file\n";print "sample SIGUSR1 sample now\n";print "update SIGUSR2 (not implemented yet)\n";print "version show version of OS-dependant module used\n";print "showargs show settings hash\n";print "\n";exit 0;}# import common functions#my $COM_LIB="./platform/common.pm";if ( -e $COM_LIB ) {eval { require $COM_LIB; };if ($@) { HotSaNICmod::dupe_control("die","can't import common library: $COM_LIB",$!,$@); }}else { HotSaNICmod::dupe_control("die","can't import common library: $COM_LIB","file not found."); }# import OS-specific functions#my $fallback=0;my $OS_LIB="./platform/$^O.pm";if ( -e $OS_LIB ) {eval { require $OS_LIB; };if ($@) {HotSaNIClog::error("can't import library: $OS_LIB",$!,$@);$fallback=1;}}else { HotSaNIClog::info("no special library available for \"$^O\""); $fallback=1; }# OS-lib not found -> try to load default lib#if ($fallback == 1) {HotSaNIClog::info("falling back to library \"default\"");eval { require "./platform/default.pm"; };if ($@) {HotSaNICmod::dupe_control("die","can't import library ./platform/default.pm",$!,$@);}}# read configuration, but don't initalize module (parameter "0")configure(0);if ( ($args =~ /version/) or (HotSaNIClog::check_debuglevel("MODULE_VERBOSE"))) {undef my @VERSIONS;push @VERSIONS,HotSaNICmod::common::version() if defined &HotSaNICmod::common::version;push @VERSIONS,HotSaNICmod::OSdep::version() if defined &HotSaNICmod::OSdep::version;push @VERSIONS,HotSaNICmod::syssnmp::version() if defined &HotSaNICmod::syssnmp::version;HotSaNIClog::info("using libs: ".join(" / ",@VERSIONS));}if ( ($args =~ /start/) or ($args =~ /nodaemon/) ) {my ($pid,$uptime)=HotSaNICmod::dupe_control("check","");if ($pid > 0) { HotSaNIClog::info("module already running on PID $pid"); }else {# initialize module#unlink "*.dat","*.old";if ( -e "init" ) {HotSaNIClog::info("-- begin init --");system "./init";HotSaNIClog::info("-- end init --");}elsif (defined &HotSaNICmod::OSdep::init) {HotSaNIClog::info("-- begin init --");HotSaNICmod::OSdep::init(%MODARGS);HotSaNIClog::info("-- end init --");}# set signal handlers and create background childprocess#$SIG{TERM} = \&terminate;$SIG{HUP} = \&configure;$SIG{USR1} = \&sample;$SIG{USR2} = \&update;if ($args =~ /start/) { fork && exit; }HotSaNICmod::dupe_control("start","");while (1 == 1) { sleep; }}}if ( $args =~ /status/) {my ($pid,$uptime)=HotSaNICmod::dupe_control("check","");if ($pid > 0) {print "module \"$MODNAME\" running on PID $pid for $uptime sec.\n";}else { print "$MODNAME: no process running.\n"; }my @DBs=HotSaNICmod::get_DBs();my ($min,$max)=HotSaNICmod::get_last_DB_changes();if ($min>=0) {print "last DB update: $min";if ($max != $min) { print " (max: $max)"; }print " seconds ago\n";print "DBs found: ",join("\n ",@DBs),"\n";}}if ( $args =~ /sample/) {my ($pid,$uptime)=HotSaNICmod::dupe_control("check","");if ($pid > 0) { kill "SIGUSR1",$pid; }else { print "$MODNAME: no process running.\n"; }}if ( $args =~ /stop/) {my ($pid,$uptime)=HotSaNICmod::dupe_control("check","");if ($pid > 0) { kill "SIGTERM",$pid; }else { print "$MODNAME: no process running.\n"; }}if ( $args =~ /configure/) {my ($pid,$uptime)=HotSaNICmod::dupe_control("check","");if ($pid > 0) { kill "SIGHUP",$pid; }else { print "$MODNAME: no process running.\n"; }}if ( $args =~ /update/) {my ($pid,$uptime)=HotSaNICmod::dupe_control("check","");if ($pid > 0) { kill "SIGUSR2",$pid; }else { print "$MODNAME: no process running.\n"; }}if ( $args =~ /showargs/) {print "---------- CONFIGURATION ----------\n";## alternative code - higher memory usage!## use Data::Dumper;# $Data::Dumper::Varname="MODARGS";# $Data::Dumper::Sortkeys=1;# print Dumper(\%MODARGS);#for (sort keys %MODARGS) {print " $_ = ".$MODARGS{$_}."\n";if (ref $MODARGS{$_} eq "ARRAY") {if (! @{$MODARGS{$_}}) { print " " x ((length $_)+5),"(empty)\n"; }foreach $line (@{$MODARGS{$_}}) { print " " x ((length $_)+5),"-> $line\n"; }}}print "-----------------------------------\n";}}######################################################################## terminate module daemon#sub terminate {HotSaNICmod::dupe_control("stop","");}######################################################################## interface to OS-dependent functions#sub sample {my $DIFF=time-$SAMPLE_LAST;if (HotSaNIClog::check_debuglevel("MODULE_SAMPLING")) {HotSaNIClog::info("last sampling $DIFF seconds ago took $SAMPLE_DURATION seconds.");}if ( $DIFF >= 9) {if ($SAMPLING == 0) {# auto throttling# skip sample if last sampling process took > 5 seconds and divide last duration by 2if ($SAMPLE_DURATION > 5) {$SAMPLE_DURATION/=2;if (HotSaNIClog::check_debuglevel("MODULE_SAMPLING")) {HotSaNIClog::warn("can't sample now, last sampling took > 5s.");}}else {$SAMPLING=1;$SAMPLE_LAST=time;HotSaNICmod::OSdep::sample(%MODARGS);if ( (defined $MODARGS{USE_SNMP}) and (defined &HotSaNICmod::syssnmp::sample) ) { HotSaNICmod::syssnmp::sample(%MODARGS); }$SAMPLING=0;$SAMPLE_DURATION=(time-$SAMPLE_LAST);}}elsif (HotSaNIClog::check_debuglevel("MODULE_SAMPLING")) {HotSaNIClog::warn("can't sample now, old sampling process running.");}}elsif (HotSaNIClog::check_debuglevel("MODULE_SAMPLING")) {HotSaNIClog::warn("can't sample now, last sample taken less than 10s ago.");}}sub update {HotSaNICmod::OSdep::update;}######################################################################## configure# - parse main settings# - parse module settings# - set module-specific configurationsub configure {$initmode=shift || 0;my @CONFmod=HotSaNICparser::read_settings(".",$MODNAME);if (scalar(@CONFmod) == 0) { HotSaNICmod::dupe_control("die","missing module settings file"); }my $modvar=$CONFglob{VARDIR}."/modules/".lc $MODNAME;$modvar=~ s/\/+/\//g;if (! -d $CONFglob{VARDIR}."/modules") { mkdir $CONFglob{VARDIR}."/modules",0755; }if (! -d $modvar) { mkdir $modvar,0755; }# configure module-specific settings#%MODARGS=HotSaNICmod::common::configure(@CONFmod);# import module's SNMP library if necessary#if (defined $MODARGS{USE_SNMP}) {my $SNMP_LIB="./platform/syssnmp.pm";$MODARGS{SNMPWALK}=$CONFglob{SNMPWALK};$MODARGS{SNMPGET}=$CONFglob{SNMPGET};if ( -e $SNMP_LIB ) {eval { require $SNMP_LIB; };if ($@) { HotSaNIClog::error("can't import library: $SNMP_LIB",$!,$@); }}else { HotSaNIClog::info("no SNMP library available"); }}# configure common module settings#foreach (@CONFmod) {($var,$value)=HotSaNICparser::parse_line($_);if ($var eq "DEBUGLEVEL") { $MODARGS{DEBUGLEVEL}=HotSaNIClog::get_debuglevel($value); }}# add global settings#$MODARGS{MODNAME}=$MODNAME;$MODARGS{VARDIR}=$modvar;$MODARGS{DEBUGLEVEL} |= HotSaNIClog::get_debuglevel($CONFglob{DEBUGLEVEL});HotSaNIClog::set_debuglevel($MODARGS{DEBUGLEVEL});if ($initmode eq "HUP") { HotSaNICmod::OSdep::init(%MODARGS) if defined &HotSaNICmod::OSdep::init; }}######################################################################## returns an array containing all "*.rrd" files in the current module's "rrd" directory#sub get_DBs {opendir(DIR,"rrd") || HotSaNICmod::dupe_control("die",$MODARGS{"MODNAME"},"error opening database dir - $!");my @DBs=grep(/\.rrd/,readdir(DIR));closedir(DIR);return @DBs;}######################################################################## returns an array containing the min and max seconds since last DB changes## if no DBs are found, (-1,-1) will be returned.#sub get_last_DB_changes {my @DBs=get_DBs();if (!@DBs) { return (-1,-1); }my ($min,$max)=(999999999999,0);foreach $test (@DBs) {(undef,undef,undef,undef,undef,undef,undef,undef,undef,$mtime,undef,undef,undef)=stat("rrd/".$test);$mtime=time-$mtime;if ($mtime<$min) { $min=$mtime; }if ($mtime>$max) { $max=$mtime; }}return ($min,$max);}######################################################################## updates a database, creates a new one if necessary## USAGE:## do_rrd($database,$maxvalue,$sampletime,@values);## $database name of the database (without ".rrd" suffix)## $maxvalue the maximum value to be expected on this datasource# (needed for DB creation)## $sampletime timestamp of the current sample## @values array of all values for this timestamp#sub do_rrd {my $dbname = shift;my $dbmax = shift;my $sampletime = shift;if ( $#_ < 0 ) {HotSaNIClog::warn("no values passed for $dbname");}my $values=join(":",@_);if (HotSaNIClog::check_debuglevel("MODULE_DB_UPDATE")) {HotSaNIClog::info("updating $dbname with $values");}# build new database if neededif ( ! -e "rrd/$dbname.rrd" ) { system("./makerrd","$dbname","$dbmax") }# update databaseRRDs::update "rrd/$dbname.rrd",$sampletime.":$values";if ($ERROR = RRDs::error) { HotSaNIClog::error("unable to update '$dbname.rrd': $ERROR"); }}1;