hotsanic |
Subversion Repositories: |
Compare with Previous - Blame - Download
#
# $Id: HotSaNICmod.pm,v 1.21 2004/02/27 09:21:47 bernisys Exp $
#
package HotSaNICmod;
use HotSaNICparser;
use RRDs;
my $MODNAME;
my %MODARGS;
($VERSION = '$Revision: 1.21 $') =~ s/.*(\d+\.\d+).*/$1/;
######################################################################
#
# control function to make sure that a module is running only once
#
# Usage:
# dupe_control($what,$module-name,$message);
#
# $what:
# start -> call this method at the head of a module to touch the
# dupe-detection checkfile.
# stop -> remove checkfile and exit normally.
# warn -> print $message as warning and continue execution.
# die -> remove checkfile and stop process with error.
#
# The given message will be preceded with a timestamp (in seconds
# since 1970) and the module-name:
#
# <time> MODULE:message\n
#
sub dupe_control {
my ($what,$mod,$message)=@_;
if (!defined $mod) { $mod="(unknown module)"; }
if (!defined $message) { $message="(unknown reason)"; }
my $pid=0;
my $delta=0;
my $line;
if ( ($what eq "check") || ($what eq "start") ) { $pid=HotSaNICparser::get_pid($MODARGS{DEBUGLEVEL}); }
if ($what eq "start") {
if ($pid > 0) { die time." $mod: process already running on PID $pid for $delta seconds.\n"; }
open FILE,">running.pid";
print FILE $$;
close FILE;
}
elsif ($what eq "stop") {
if (-e "running.pid") { unlink "running.pid"; }
exit 0;
}
elsif ($what eq "die") {
if (-e "running.pid") { unlink "running.pid"; }
die time." $mod: $message\n";
}
elsif ($what eq "warn") {
print time," $mod warn: $message\n";
}
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 { print time," $mod: method \"$what\" not supported.\n"; }
}
######################################################################
#
# check cmdline arguments
#
sub init {
$args=shift || "";
$MODNAME=HotSaNICparser::get_module_name()."";
my $found=0;
my @possible_args=("start","stop","status","configure","sample","update","version","help","showargs");
foreach (@possible_args) {
if ($args eq $_) { $found++; }
}
if ($found == 0) { $args=""; }
# import common functions
#
my $COM_LIB="./platform/common.pm";
if ( -e $COM_LIB ) {
eval { require $COM_LIB; };
if ($@) { HotSaNICmod::dupe_control("die",$MODNAME,"Error importing common library: $COM_LIB.\n\t$!\n$@\n"); }
}
else { HotSaNICmod::dupe_control("die",$MODNAME,"Error importing common library: $COM_LIB.\n\tfile not found.\n"); }
configure();
# import OS-specific functions
#
my $fallback=0;
my $OS_LIB="./platform/$^O.pm";
if ( -e $OS_LIB ) {
eval { require $OS_LIB; };
if ($@) { print "Error importing library: $OS_LIB\n\t$!\n$@\n"; $fallback=1; }
}
else { print "$MODNAME: Operating system \"$^O\" not supported!\n"; $fallback=1; }
# OS-lib not found -> try to load default lib
#
if ($fallback == 1) {
print "$MODNAME: Falling back to \"default\"\n";
eval { require "./platform/default.pm"; };
if ($@) { HotSaNICmod::dupe_control("die",$MODNAME,"Error importing default module.\n$@\n"); }
}
if ( $args eq "" ) {
print "arguments missing!\n";
print "usage: $0 [start/stop/status/configure/sample/update/version/help/showargs]\n";
print "\n";
}
if ( $args =~ /help/) {
print "usage: $0 [start/stop/status/configure/sample/update/version/help/showargs]\n";
print "\n";
print "alternative usage: send a signal to <module PID>\n";
print "\n";
print "argument signal function\n";
print "--------- ------- --------------------------------------------------\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";
}
if ( ($args =~ /version/) or ($MODARGS{DEBUGLEVEL} > 0) ) {
push my @VERSIONS,HotSaNICmod::OSdep::version() if defined &HotSaNICmod::OSdep::version;
push @VERSIONS,HotSaNICmod::common::version() if defined &HotSaNICmod::common::version;
push @VERSIONS,syssnmp::version() if defined &syssnmp::version;
print "$MODNAME: using libs: ",join(" / ",@VERSIONS),"\n";
}
if ( $args =~ /start/) {
my ($pid,$uptime)=HotSaNICmod::dupe_control("check",$MODNAME,"");
if ($pid > 0) { print "$MODNAME: module already running on PID $pid\n"; }
else {
HotSaNICmod::daemonize();
HotSaNICmod::dupe_control("start",$MODNAME,"");
while (1 == 1) { sleep; }
}
}
if ( $args =~ /status/) {
my ($pid,$uptime)=HotSaNICmod::dupe_control("check",$MODNAME,"");
if ($pid > 0) {
print "$MODNAME: module 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",$MODNAME,"");
if ($pid > 0) { kill "SIGUSR1",$pid; }
else { print "$MODNAME: no process running.\n"; }
}
if ( $args =~ /stop/) {
my ($pid,$uptime)=HotSaNICmod::dupe_control("check",$MODNAME,"");
if ($pid > 0) { kill "SIGTERM",$pid; }
else { print "$MODNAME: no process running.\n"; }
}
if ( $args =~ /configure/) {
my ($pid,$uptime)=HotSaNICmod::dupe_control("check",$MODNAME,"");
if ($pid > 0) { kill "SIGHUP",$pid; }
else { print "$MODNAME: no process running.\n"; }
}
if ( $args =~ /update/) {
my ($pid,$uptime)=HotSaNICmod::dupe_control("check",$MODNAME,"");
if ($pid > 0) { kill "SIGUSR2",$pid; }
else { print "$MODNAME: no process running.\n"; }
}
if ( $args =~ /showargs/) {
for (sort keys %MODARGS) { print "$_ = ".$MODARGS{$_}."\n"; }
}
}
######################################################################
#
# fork into background
#
sub daemonize {
# set signal handlers and create background childprocess
#
$SIG{TERM} = \&terminate;
$SIG{HUP} = \&configure;
$SIG{USR1} = \&sample;
$SIG{USR2} = \&update;
fork && exit 0;
}
######################################################################
#
# terminate module daemon
#
sub terminate {
HotSaNICmod::dupe_control("stop",$MODNAME,"");
}
######################################################################
#
# interface to OS-dependent functions
#
sub sample {
HotSaNICmod::OSdep::sample(%MODARGS);
}
sub update {
HotSaNICmod::OSdep::update;
}
######################################################################
#
# configure
# - parse main settings
# - parse module settings
# - set module-specific configuration
sub configure {
my @CONFmod=HotSaNICparser::read_settings(".",$MODNAME);
my %CONFglob=HotSaNICparser::get_config("../..",$MODNAME);
if (scalar(@CONFmod) == 0) { HotSaNICmod::dupe_control("die",$MODNAME,"missing settings file"); }
if (scalar(keys(%CONFglob)) == 0) { HotSaNICmod::dupe_control("die",$MODNAME,"missing settings file"); }
if (! -d $CONFglob{VARDIR}."/modules/system") { mkdir $CONFglob{VARDIR}."/modules/system",0755; }
# configure module-specific settings
#
%MODARGS=HotSaNICmod::common::configure(@CONFmod);
# configure common module settings
#
foreach (@CONFmod) {
($var,$value)=HotSaNICparser::parse_line($_);
if ($var eq "DEBUGLEVEL") { $MODARGS{DEBUGLEVEL}=$value; }
}
# add global settings
#
$MODARGS{MODNAME}=$MODNAME;
$MODARGS{VARDIR}=$CONFglob{VARDIR}."/modules/system";
$MODARGS{SNMPWALK}=$CONFglob{SNMPWALK};
$MODARGS{SNMPGET}=$CONFglob{SNMPGET};
if ( (!defined $MODARGS{DEBUGLEVEL}) || ($CONFglob{DEBUGLEVEL} > $MODARGS{DEBUGLEVEL}) ) { $MODARGS{DEBUGLEVEL}=$CONFglob{DEBUGLEVEL}; }
if (!defined $MODARGS{DEBUGLEVEL}) { $MODARGS{DEBUGLEVEL}=-1; }
}
######################################################################
#
# 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 $time = shift;
my $values=join(":",@_);
# build new database if needed
if ( ! -e "rrd/$dbname.rrd" ) { system("./makerrd","$dbname","$dbmax") }
# update database
RRDs::update "rrd/$dbname.rrd", $time.":".$values;
if ($ERROR = RRDs::error) { print $time," ",$MODNAME,": unable to update '$dbname.rrd': $ERROR\n"; }
}
1;