hotsanic |
Subversion Repositories: |
Compare with Previous - Blame - Download
#
# $Id: HotSaNIC.pm,v 1.2 2002/11/24 18:50:06 tinheap Exp $
#
package HotSaNIC;
use Exporter;
# our ($VERSION, @ISA, @EXPORT);
($VERSION = '$Revision: 1.2 $') =~ s/.*(\d+\.\d+).*/$1/;
@ISA = qw(Exporter);
@EXPORT = qw (
snmp_sysbulk
snmp_sysquery
get_module_name
get_config
read_settings
check_config
strip_unwanted
identify_os_type
parse_line
get_diagram_properties
opt2arg
arg2opt
check_args
dupe_control
convert_units
);
######################################################################
#
# 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=get_module_name(); }
if (!defined $message) { $message="(unknown reason)"; }
if ($what eq "start") {
if (-e "running.dat") {
open FILE,"running.dat";
$pid=<FILE>;
close FILE;
chomp $pid;
if ((defined $pid) && ($pid ne "") && (-e "/proc/$pid")) {
open FILE,"/proc/$pid/stat";
$line=<FILE>;
close FILE;
if( index($line,"read-data") >= 0) {
@fileds=split / /,$line;
$starttime=$fileds[21]/100;
open FILE,"/proc/uptime";
$line=<FILE>;
close FILE;
($uptime)=split / /,$line;
$delta=int(($uptime-$starttime)*100)/100;
if ( ($uptime-$starttime) > 3600) {
print time," ",$mod,": process running >1 hour --> KILLING!\n";
system "kill -9 $pid";
}
else {
print time," ",$mod,": process already running on PID $pid for $delta seconds.\n";
exit 1;
}
}
}
}
open FILE,">running.dat";
print FILE $$;
close FILE;
}
elsif ($what eq "stop") {
if (-e "running.dat") { unlink "running.dat"; }
exit 0;
}
elsif ($what eq "die") {
if (-e "running.dat") { unlink "running.dat"; }
die time." ".$mod.": ".$message."\n";
}
elsif ($what eq "warn") {
print time," ",$mod," warn: ",$message,"\n";
}
else { print time," ",$mod," method \"",$what,"\" not supported.\n"; }
}
######################################################################
#
# checks if all necessary arguments are given in the corosponding
# hash. If not, try to reconstruct them or to set defaults.
#
# Usage:
# %arguments=check_args(%arguments);
#
sub check_args {
($check,%ARGS)=@_;
foreach $value (split /,/,$check) {
if ( (!defined $ARGS{$value}) || ($ARGS{$value} eq "") || ($ARGS{$value} eq "not configured") ) {
if ($value eq "MODNAME") { $ARGS{$value}=get_module_name(); }
if ($value eq "DEBUGLEVEL") { $ARGS{$value}=-1; }
if ($value eq "OSTYPE") { $ARGS{$value}=identify_os_type(); }
if ($value eq "SNMPWALK") {
my @found=grep /snmpwalk$/, `locate bin\/snmpwalk`;
if (@found) { $found=$found[0];chomp $found; $result=" Found: ".$found; $ARGS{$value}=$found; } else { $ARGS{$value}="echo >/dev/null"; }
dupe_control("warn",$ARGS{"MODNAME"},"SNMPWALK not given on commandline! $result");
}
if ($value eq "SNMPGET") {
my @found=grep /snmpget$/, `locate bin\/snmpget`;
if (@found) { $found=$found[0];chomp $found; $result=" Found: ".$found; $ARGS{$value}=$found; } else { $ARGS{$value}="echo >/dev/null"; }
dupe_control("warn",$ARGS{"MODNAME"},"SNMPGET not given on commandline! $result");
}
}
}
return %ARGS;
}
######################################################################
#
# converts an option-hash to cmdline argument string which can be
# passed to a module script
#
# Usage:
# $commandline_args=opt2arg(%options);
#
sub opt2arg {
my $line="";
my %opts=@_;
foreach $var (keys(%opts)) {
if (index("DEBUGLEVEL MODNAME OSTYPE SNMPWALK SNMPGET",$var) >= 0) {
$line=$line." ".$var."=\"".$opts{$var}."\"";
}
}
if ($opts{"DEBUGLEVEL"}>=0) { print "CLIENT-LINE: $line\n" };
return $line;
}
######################################################################
#
# converts cmdline arguments array to an options-hash
#
# Usage:
# %options=arg2opt($commandline_args)
#
sub arg2opt {
my %HASH;
foreach $pair (@_) {
($var,$value)=split /=/, $pair;
$HASH{$var}=$value;
}
if (! defined $HASH{"MODNAME"}) { $HASH{"MODNAME"}=get_module_name(); }
if (! defined $HASH{"OSTYPE"}) { $HASH{"OSTYPE"}=`uname`; chomp $HASH{"OSTYPE"}; }
if (! defined $HASH{"DEBUGLEVEL"}) { $HASH{"DEBUGLEVEL"}=-1; }
if ($HASH{"DEBUGLEVEL"} >=6 ) {
print "\n";
foreach (keys %HASH) { printf " %-15s %s\n",$_,$HASH{$_}; }
}
return %HASH;
}
######################################################################
#
# evaluates some diagram properties from the given range
#
# Usage:
# ($description,$file_description,$build_interval,$diagram_range)=get_diagram_properties($range);
#
sub get_diagram_properties {
my ($range)=@_;
my ($descr,$file,$build,$fullrange);
if ($range eq "1h") { $descr="hour"; $file=$descr; $build=0; $fullrange=3600; }
elsif ($range eq "6h") { $descr="6 hours"; $file="6h"; $build=30; $fullrange=21600; }
elsif ($range eq "1day") { $descr="day"; $file=$descr; $build=120; $fullrange=86400; }
elsif ($range eq "1week") { $descr="week"; $file=$descr; $build=1000; $fullrange=604800; }
elsif ($range eq "1month") { $descr="month"; $file=$descr; $build=4300; $fullrange=2592000; }
elsif ($range eq "1year") { $descr="year"; $file=$descr; $build=52500; $fullrange=31536000; }
return ($descr,$file,$build,$fullrange);
}
######################################################################
#
# Query remote host via SNMP and store data in tempfile
# GetBulk method
#
# Usage:
#
# snmp_sysbulk($path_to_snmpbulkget,$host,$community,$OIDs,$nums);
#
# syscall: snmpbulkget $host $community with all $OIDs permutated
# with all $nums
#
# $nums refers to the last part of the OIDs.
#
# $OIDs and $nums have to be given space-separated.
#
sub snmp_sysbulk {
my ($binpath,$host,$community,$OIDs,$nums)=@_;
my $query="";
my @OIDs=split / /,$OIDs;
my @nums=split / /,$nums;
my $OIDcount=(@OIDs);
foreach $num (@nums) {
foreach $OID (@OIDs) {
$query=$query.$OID.".".$num." ";
}
}
my @result=`$binpath $host $community $query`;
$num=0;
$count=0;
foreach (@result) {
chomp;
s/.* = //;
$num++;
if ($num==1) { $line=$nums[$count]; $count++ }
$line=$line." ".$_;
if ($num>=$OIDcount) {$num=0; push @results,$line;}
}
return @results;
}
######################################################################
#
# Query remote host via SNMP and store data in tempfile
# snmpwalk method
#
# Usage:
#
# snmp_sysquery($path_to_snmpwalk,$host,$community,$item,@grep)
#
# $item: refers to the MIB you want to query ommitting the last part
# of the OID
#
# @grep: an array of the OID's last parts you's like to query.
#
sub snmp_sysquery {
my ($binpath,$host,$community,$item,@grep)=@_;
@result=`$binpath $host $community $item`;
foreach $contains (@grep) {
foreach (grep /$contains/, @result) {
chomp;
if (/\.([0-9]*) = /, $num=$1) {
($var,$value)=split / = /;
if (defined $lines{$num}) { $lines{$num}=$lines{$num}." $value"; } else { $lines{$num}=$value; }
}
}
}
foreach $line (keys %lines) {
push @results,$line." ".$lines{$line};
}
return @results;
}
######################################################################
#
# evaluate name of module by its subdir
#
# Usage:
#
# $modname=get_module_name();
#
sub get_module_name {
my $pwd=uc `pwd`;
chomp $pwd;
my (undef,$name)=split /MODULES\//,$pwd;
return $name;
}
######################################################################
#
# strip unwanted chars like " and multiple spaces at end / beginning
# of each element and return the processed array.
#
# Usage:
#
# $stripped_string=strip_unwanted($raw_string);
#
sub strip_unwanted {
foreach (@_) {
$_ =~ s/ *= */=/g; # spaces near a =
$_ =~ s/\"//g; # " chars
$_ =~ s/ +/ /g; # multiple spaces to single
$_ =~ s/^ *//g; # spaces at beginning
$_ =~ s/ *$//g; # spaces at end
}
return @_;
}
######################################################################
#
# Parse a line, strip all unwanted chars, split it by "=" into
# a VAR and a VALUE part and make sure those parts are defined.
#
# Usage:
#
# ($var,$value,$comment)=parse_line($settings_line);
#
sub parse_line {
my ($line)=@_;
chomp $line;
# remove leading spaces
$line =~ s/^ *//g;
# weed out comments (i.e. everything following a "#"
my ($important,$comment)=split /#/,$line,2;
if ((! defined $comment) || ( $comment eq "" )) {
if (index($line,"#")>=0) { $comment=" "; }
else { $comment=""; }
}
if ((! defined $important) || ($important eq "")) { return ("","",$comment); }
# trim the edges ;)
($important)=strip_unwanted($important);
# separate the variable name from its assigned value
my ($var,$value)=split /=/,$important,2;
# avoid undefined variables
$var="" if (! defined $var);
$value="" if (! defined $value);
# force varnames to be upcase
$var=uc $var;
return ($var,$value,$comment)
}
######################################################################
#
# evaluate settings file and check config...
#
# Usage:
#
# %config=get_config($path_to_settings_file);
#
sub get_config {
my ($location)=@_;
my ($var,$value,$BINPATH,$DAEMONDIR,$LOGDIR,$PIDFILE,$DTIME,$CTIME,$STIME,$WEBDIR,$ORDER,$LOGSIZE,$LOGBACKUPS);
my @lines=read_settings($location);
foreach (@lines) {
($var,$value)=parse_line($_);
$config{$var}=$value;
}
# sanity check for all config variables
#
$config{"BINPATH"}=check_config_item("BINPATH","path","","","path to \"rrdtool\"",%config);
$config{"DAEMONDIR"}=check_config_item("DAEMONDIR","path","","","path to \"HotSaNIC\"",%config);
$config{"WEBDIR"}=check_config_item("WEBDIR","path","","","path to HotSaNIC's output directory",%config);
$config{"LOGDIR"}=check_config_item("LOGDIR","path","\$DAEMONDIR/log","","path to HotSaNIC's logfiles",%config);
$config{"PIDFILE"}=check_config_item("PIDFILE","var","\$DAEMONDIR/log/rrdtimer.pid","","path to HotSaNIC's PID file",%config);
$config{"DTIME"}=60*check_config_item("DTIME","var","15","minutes","diagram rebuild time",%config);
$config{"CTIME"}=3600*check_config_item("CTIME","var","12","hours","diagram conversion time",%config);
$config{"STIME"}=check_config_item("STIME","var","120","seconds","module scan time",%config);
$config{"LOGSIZE"}=check_config_item("LOGSIZE","var","500000","bytes","max. logfile size",%config);
$config{"LOGBACKUPS"}=check_config_item("LOGBACKUPS","var","4","","logfiles to keep as backups",%config);
$config{"IMAGEFORMAT"}=check_config_item("IMAGEFORMAT","var","gif","","format of generated pictures",%config);
$config{"ORDER"}=check_config_item("ORDER","var","","","order of modules",%config);
$config{"DEBUGLEVEL"}=check_config_item("DEBUGLEVEL","var","-1","","debug level",%config);
return %config;
}
######################################################################
#
# read settings-file and strip comments and empty entries
#
# Usage:
#
# @parsed_config=read_settings($path_to_settings_file,$module_name);
#
# returns just the lines actually containing data - stripped by comments.
#
sub read_settings {
my ($location,$modname)=@_;
if (!defined $modname) {
$modname="rrdtimer";
$error="Configuration file \"settings\" missing in HotSaNIC's main directory. Probably you have to run setup.pl first.\n";
}
else { $error="Configuration file \"settings\" missing in module.\n"; }
if ( (! defined $location) || ($location eq "")) { $location="."; }
open CONF,"$location/settings" or dupe_control("die",$modname,$error);
while (<CONF>) {
chomp;
next if $_ eq "";
my ($important,$comment)=split /#/;
if ((defined $important) && ( index($important,"=") >= 0)) {
push @config,$important
}
}
close CONF;
return @config;
}
######################################################################
#
# sanity check config-item
#
# Usage:
#
# $value=check_config_item($item_name,$type,$default_value,$unit,$description,%config_hash);
#
# $type:
# "path" -> assume that value is a path -> check its existence.
# "var" -> assume that value is a variable -> check if the value is set correctly.
#
# if a fatal config-error is detected, the program dies with an error.
#
sub check_config_item {
my ($name,$type,$default,$unit,$description,%confhash)=@_;
my $DAEMONDIR=$confhash{"DAEMONDIR"};
my $var=$confhash{$name};
if (defined $var) { $var=~ s/\$DAEMONDIR/$DAEMONDIR/g; }
if ($type eq "path") {
if ((! defined $var) || ($var eq "")) {
print $name," (",$description,") not configured.\n";
if ($default eq "") { print "no default value given.\n"; exit 1; }
else { print "using default value: ",$default," ",$unit,"\n"; ($var=$default)=~ s/\$DAEMONDIR/$DAEMONDIR/g; }
}
if ( ! -e $var) { print $name," (",$description,") does not exist.\n"; exit 1; }
}
if ($type eq "var") {
if ((! defined $var) || ($var eq "")) {
print $name," (",$description,") not configured.\n";
if ($default eq "") { print "no default value given.\n"; exit 1; }
else { print "using default value: ",$default," ",$unit,"\n"; $var=$default; }
}
}
return $var;
}
######################################################################
#
# identify OS type
#
# Usage:
#
# $ostype=identify_os_type();
#
sub identify_os_type {
my $os=`uname`;
chomp $os;
return $os;
}
######################################################################
#
# convert - converts GB/MB/KB into Bytes
#
# Usage:
#
# @out=convert_units(@in);
#
# all values in @in will be checked against existance of a SI-multiplier
# (K, M or G) and the value stored in @out are multiplied accordingly.
#
sub convert_units {
my @in = @_;
my @out = ();
foreach $i (@in) {
$i =~ s/(^\d+)K/$1 * 1024/;
$i =~ s/(^\d+)M/$1 * 1024 * 1024/;
$i =~ s/(^\d+)G/$1 * 1024 * 1024 * 1024/;
#print "$i\n";
$bytes = (eval "$i");
#print "$bytes\n";
push @out, $bytes;
}
return @out;
}
1;