diff options
author | Niko Tyni <ntyni@iki.fi> | 2005-09-04 18:23:12 +0200 |
---|---|---|
committer | Niko Tyni <ntyni@iki.fi> | 2005-09-04 18:23:12 +0200 |
commit | 52de638f8e7e13dd62a4e7906387be72969a4168 (patch) | |
tree | 129599b69e7323fb6500336e0baaffcf55335bea /lib/Smokeping.pm | |
parent | 09504475c41653b151b02605ea1ea7b53f86e222 (diff) | |
parent | 0fb4bc74b24ea96e80d4e27428b8c2451fbf0eb5 (diff) | |
download | smokeping-52de638f8e7e13dd62a4e7906387be72969a4168.tar.gz smokeping-52de638f8e7e13dd62a4e7906387be72969a4168.tar.xz |
Copied branches/2.0 to trunk/software
Diffstat (limited to 'lib/Smokeping.pm')
-rw-r--r-- | lib/Smokeping.pm | 471 |
1 files changed, 319 insertions, 152 deletions
diff --git a/lib/Smokeping.pm b/lib/Smokeping.pm index 8cd5897..28923e7 100644 --- a/lib/Smokeping.pm +++ b/lib/Smokeping.pm @@ -9,18 +9,25 @@ use Digest::MD5 qw(md5_base64); use SNMP_util; use SNMP_Session; use POSIX; -use ISG::ParseConfig; +use Config::Grammar; use RRDs; use Sys::Syslog qw(:DEFAULT setlogsock); + setlogsock('unix') if grep /^ $^O $/xo, ("linux", "openbsd", "freebsd", "netbsd"); + +# make sure we do not end up with , in odd places where one would expect a '.' +# we set the environment variable so that our 'kids' get the benefit too +$ENV{LC_NUMERIC}='C'; +POSIX::setlocale(&POSIX::LC_NUMERIC,""); + use File::Basename; use Smokeping::Examples; use Smokeping::RRDtools; # globale persistent variables for speedy use vars qw($cfg $probes $VERSION $havegetaddrinfo $cgimode); -$VERSION="1.99001"; +$VERSION="1.99006"; # we want opts everywhere my %opt; @@ -50,6 +57,10 @@ sub find_libdir { sub do_log(@); sub load_probe($$$$); +sub dummyCGI::param { + return wantarray ? () : ""; +} + sub load_probes ($){ my $cfg = shift; my %prbs; @@ -99,6 +110,11 @@ sub lnk ($$) { } } +sub dyndir ($) { + my $cfg = shift; + return $cfg->{General}{dyndir} || $cfg->{General}{datadir}; +} + sub update_dynaddr ($$){ my $cfg = shift; my $q = shift; @@ -107,14 +123,19 @@ sub update_dynaddr ($$){ my $address = $ENV{REMOTE_ADDR}; my $targetptr = $cfg->{Targets}; foreach my $step (@target){ - return "Error: Unknown Target $step" + return "Error: Unknown target $step" unless defined $targetptr->{$step}; $targetptr = $targetptr->{$step}; }; - return "Error: Invalid Target" + return "Error: Invalid target or secret" unless defined $targetptr->{host} and $targetptr->{host} eq "DYNAMIC/${secret}"; - my $file = $cfg->{General}{datadir}."/".(join "/", @target); + my $file = dyndir($cfg); + for (0..$#target-1) { + $file .= "/" . $target[$_]; + ( -d $file ) || mkdir $file, 0755; + } + $file.= "/" . $target[-1]; my $prevaddress = "?"; my $snmp = snmpget_ident $address; if (-r "$file.adr" and not -z "$file.adr"){ @@ -342,7 +363,7 @@ sub init_target_tree ($$$$) { foreach my $prop (keys %{$tree}) { if (ref $tree->{$prop} eq 'HASH'){ - if (not -d $name) { + if (not -d $name and not $cgimode) { mkdir $name, 0755 or die "ERROR: mkdir $name: $!\n"; }; init_target_tree $cfg, $probes, $tree->{$prop}, "$name/$prop"; @@ -381,6 +402,7 @@ sub init_target_tree ($$$$) { my $comparison = Smokeping::RRDtools::compare($name.".rrd", \@create); die("Error: RRD parameter mismatch ('$comparison'). You must delete $name.rrd or fix the configuration parameters.\n") if $comparison; + Smokeping::RRDtools::tuneds($name.".rrd", \@create); } } } @@ -542,6 +564,9 @@ sub get_overview ($$$$){ my $date = $cfg->{Presentation}{overview}{strftime} ? POSIX::strftime($cfg->{Presentation}{overview}{strftime}, localtime(time)) : scalar localtime(time); + if ( $RRDs::VERSION >= 1.199908 ){ + $date =~ s|:|\\:|g; + } foreach my $prop (sort {$tree->{$a}{_order} <=> $tree->{$b}{_order}} grep { ref $tree->{$_} eq 'HASH' and defined $tree->{$_}{host}} keys %$tree) { @@ -556,9 +581,11 @@ sub get_overview ($$$$){ '--start','-'.exp2seconds($cfg->{Presentation}{overview}{range}), '--title',$tree->{$prop}{title}, '--height',$cfg->{Presentation}{overview}{height}, - '--width',,$cfg->{Presentation}{overview}{width}, + '--width',$cfg->{Presentation}{overview}{width}, '--vertical-label',"Seconds", '--imgformat','PNG', + '--alt-autoscale-max', + '--alt-y-grid', '--lower-limit','0', "DEF:median=${rrd}:median:AVERAGE", "DEF:loss=${rrd}:loss:AVERAGE", @@ -566,11 +593,10 @@ sub get_overview ($$$$){ "CDEF:dm=median,0,$max,LIMIT", "CDEF:dm2=median,1.5,*,0,$max,LIMIT", "LINE1:dm2", # this is for kicking things down a bit - "LINE1:dm#$medc:median RTT avg\\: ", - "GPRINT:median:AVERAGE: %0.2lf %ss ", - "GPRINT:median:LAST: latest RTT\\: %0.2lf %ss ", - "GPRINT:ploss:AVERAGE: avg pkg loss\\: %.2lf %% ", - "COMMENT: $date\\j"); + "LINE1:dm#$medc:median RTT", + "GPRINT:median:AVERAGE:avg RTT\\: %.2lf %ss", + "GPRINT:ploss:AVERAGE:avg pkt loss\\: %.2lf %%", + "COMMENT:$date\\j"); my $ERROR = RRDs::error(); $page .= "<div>"; if (defined $ERROR) { @@ -645,26 +671,46 @@ sub smokecol ($) { return \@items; } +sub parse_datetime($){ + my $in = shift; + for ($in){ + /^\s*(\d{4})-(\d{1,2})-(\d{1,2})(?:\s+(\d{1,2}):(\d{2})(?::(\d{2}))?)?\s*$/ && + return POSIX::mktime($6||0,$5||0,$4||0,$3,$2-1,$1-1900,0,0,-1); + /([ -:a-z0-9]+)/ && return $1; + }; +} + sub get_detail ($$$$){ + # when drawing the detail page there are two modes for doing it + # a) classic with several static graphs on the page + # b) with one graph and below the graph one can specify the end time + # and the length of the graph. my $cfg = shift; my $q = shift; my $tree = shift; my $open = shift; + return "" unless $tree->{host}; + my @dirs = @{$open}; my $file = pop @dirs; my $dir = ""; - die "ERROR: ".(join ".", @dirs)." has no probe defined\n" + + return "<div>ERROR: ".(join ".", @dirs)." has no probe defined</div>" unless $tree->{probe}; - die "ERROR: ".(join ".", @dirs)." $tree->{probe} is not known\n" + + return "<div>ERROR: ".(join ".", @dirs)." $tree->{probe} is not known</div>" unless $cfg->{__probes}{$tree->{probe}}; + my $probe = $cfg->{__probes}{$tree->{probe}}; my $ProbeDesc = $probe->ProbeDesc(); my $step = $probe->step(); my $pings = $probe->_pings($tree); - my $page; + my $mode = $q->param('displaymode') || 's'; + return "<div>ERROR: unknown displaymode $mode</div>" + unless $mode =~ /^[sn]$/; for (@dirs) { $dir .= "/$_"; @@ -674,142 +720,190 @@ sub get_detail ($$$$){ unless -d $cfg->{General}{imgcache}.$dir; } - my $rrd = $cfg->{General}{datadir}."/".(join "/", @dirs)."/${file}.rrd"; - my $img = $cfg->{General}{imgcache}."/".(join "/", @dirs)."/${file}.rrd"; - - my %lasthight; - if (open (HG,"<${img}.maxhight")){ - while (<HG>){ - chomp; - my @l = split / /; - $lasthight{$l[0]} = $l[1]; - } - close HG; - } - my $max = findmax $cfg, $rrd; - if (open (HG,">${img}.maxhight")){ - foreach my $s (keys %{$max}){ - print HG "$s $max->{$s}\n"; - } - close HG; - } + my $rrd = $cfg->{General}{datadir}."/".$dir."/${file}.rrd"; + + my $imgbase; + my $imghref; + my $max; + my @tasks; + my %lasthight; + + if ($mode eq 's'){ + # in nave mode there is only one graph, so the height calculation + # is not necessary. + $imgbase = $cfg->{General}{imgcache}."/".(join "/", @dirs)."/${file}"; + $imghref = $cfg->{General}{imgurl}."/".(join "/", @dirs)."/${file}"; + @tasks = @{$cfg->{Presentation}{detail}{_table}}; + if (open (HG,"<${imgbase}.maxhight")){ + while (<HG>){ + chomp; + my @l = split / /; + $lasthight{$l[0]} = $l[1]; + } + close HG; + } + $max = findmax $cfg, $rrd; + if (open (HG,">${imgbase}.maxhight")){ + foreach my $s (keys %{$max}){ + print HG "$s $max->{$s}\n"; + } + close HG; + } + } else { + mkdir $cfg->{General}{imgcache}."/__navcache",0755 unless -d $cfg->{General}{imgcache}."/__navcache"; + # remove old images after one hour + my $pattern = $cfg->{General}{imgcache}."/__navcache/*.png"; + for (glob $pattern){ + unlink $_ if time - (stat $_)[9] > 3600; + } + $imgbase =$cfg->{General}{imgcache}."/__navcache/".time()."$$"; + $imghref =$cfg->{General}{imgurl}."/__navcache/".time()."$$"; + @tasks = (["Navigator Mode", parse_datetime($q->param('start')),parse_datetime($q->param('end'))]); + my ($graphret,$xs,$ys) = RRDs::graph + ("dummy", + '--start', $tasks[0][1], + '--end',$tasks[0][2], + "DEF:maxping=${rrd}:median:AVERAGE", + 'PRINT:maxping:MAX:%le' ); + my $ERROR = RRDs::error(); + return "<div>RRDtool did not understand your input: $ERROR.</div>" if $ERROR; + my $val = $graphret->[0]; + $val = 1 if $val =~ /nan/i; + $max = { $tasks[0][1] => $val * 1.5 }; + } + my $smoke = $pings >= 3 - ? smokecol $pings : - [ 'COMMENT:(Not enough pings to draw any smoke.)\s', 'COMMENT:\s' ]; - # one \s doesn't seem to be enough + ? smokecol $pings : + [ 'COMMENT:(Not enough pings to draw any smoke.)\s', 'COMMENT:\s' ]; + # one \s doesn't seem to be enough my @upargs; my @upsmoke; - my @median; - my $date = $cfg->{Presentation}{detail}{strftime} ? - POSIX::strftime($cfg->{Presentation}{detail}{strftime}, - localtime(time)) : scalar localtime(time); - - for (@{$cfg->{Presentation}{detail}{_table}}) { - my ($desc,$start) = @{$_}; - $start = exp2seconds($start); - do { - @median = ("DEF:median=${rrd}:median:AVERAGE", - "DEF:loss=${rrd}:loss:AVERAGE", - "CDEF:ploss=loss,$pings,/,100,*", - "GPRINT:median:AVERAGE:Median Ping RTT (avg %.1lf %ss) ", - "LINE1:median#202020" - ); + my %lc; + if ( defined $cfg->{Presentation}{detail}{loss_colors}{_table} ) { + for (@{$cfg->{Presentation}{detail}{loss_colors}{_table}}) { + my ($num,$col,$txt) = @{$_}; + $lc{$num} = [ $txt, "#".$col ]; + } + } else { my $p = $pings; + %lc = (0 => ['0', '#26ff00'], + 1 => ["1/$p", '#00b8ff'], + 2 => ["2/$p", '#0059ff'], + 3 => ["3/$p", '#5e00ff'], + 4 => ["4/$p", '#7e00ff'], + int($p/2) => [int($p/2)."/$p", '#dd00ff'], + $p-1 => [($p-1)."/$p", '#ff0000'], + ); + }; - my %lc; - my $lastup = 0; - if ( defined $cfg->{Presentation}{detail}{loss_colors}{_table} ) { - for (@{$cfg->{Presentation}{detail}{loss_colors}{_table}}) { - my ($num,$col,$txt) = @{$_}; - $lc{$num} = [ $txt, "#".$col ]; - } - } else { - %lc = (0 => ['0', '#26ff00'], - 1 => ["1/$p", '#00b8ff'], - 2 => ["2/$p", '#0059ff'], - 3 => ["3/$p", '#5e00ff'], - 4 => ["4/$p", '#7e00ff'], - int($p/2) => [int($p/2)."/$p", '#dd00ff'], - $p-1 => [($p-1)."/$p", '#ff0000'], + my %upt; + if ( defined $cfg->{Presentation}{detail}{uptime_colors}{_table} ) { + for (@{$cfg->{Presentation}{detail}{uptime_colors}{_table}}) { + my ($num,$col,$txt) = @{$_}; + $upt{$num} = [ $txt, "#".$col]; + } + } else { + %upt = ( 3600 => ['<1h', '#FFD3D3'], + 2*3600 => ['<2h', '#FFE4C7'], + 6*3600 => ['<6h', '#FFF9BA'], + 12*3600 => ['<12h','#F3FFC0'], + 24*3600 => ['<1d', '#E1FFCC'], + 7*24*3600 => ['<1w', '#BBFFCB'], + 30*24*3600 => ['<1m', '#BAFFF5'], + '1e100' => ['>1m', '#DAECFF'] + ); + } + + my $date = $cfg->{Presentation}{detail}{strftime} ? + POSIX::strftime($cfg->{Presentation}{detail}{strftime}, + localtime(time)) : scalar localtime(time); + my $BS = ''; + if ( $RRDs::VERSION >= 1.199908 ){ + $date =~ s|:|\\:|g; + $ProbeDesc =~ s|:|\\:|g; + $BS = '\\'; + } + + for (@tasks) { + my ($desc,$start,$end) = @{$_}; + $end ||= 'last'; + $start = exp2seconds($start) if $mode eq 's'; + + my $startstr = $start =~ /^\d+$/ ? POSIX::strftime("%Y-%m-%d %H:%M",localtime($mode eq 'n' ? $start : time-$start)) : $start; + my $endstr = $end =~ /^\d+$/ ? POSIX::strftime("%Y-%m-%d %H:%M",localtime($mode eq 'n' ? $end : time)) : $end; + + my $last = -1; + my $swidth = $max->{$start} / $cfg->{Presentation}{detail}{height}; + my @median = ("DEF:median=${rrd}:median:AVERAGE", + "DEF:loss=${rrd}:loss:AVERAGE", + "CDEF:ploss=loss,$pings,/,100,*", + "GPRINT:median:AVERAGE:Median Ping RTT (%.1lf %ss avg) ", + "LINE1:median#202020" ); - }; - my $last = -1; - my $swidth = $max->{$start} / $cfg->{Presentation}{detail}{height}; foreach my $loss (sort {$a <=> $b} keys %lc){ next if $loss >= $pings; - my $lvar = $loss; $lvar =~ s/\./d/g ; + my $lvar = $loss; $lvar =~ s/\./d/g ; push @median, - ( - "CDEF:me$lvar=loss,$last,GT,loss,$loss,LE,*,1,UNKN,IF,median,*", - "CDEF:meL$lvar=me$lvar,$swidth,-", - "CDEF:meH$lvar=me$lvar,0,*,$swidth,2,*,+", - "AREA:meL$lvar", - "STACK:meH$lvar$lc{$loss}[1]:$lc{$loss}[0]" - ); - $last = $loss; + ( + "CDEF:me$lvar=loss,$last,GT,loss,$loss,LE,*,1,UNKN,IF,median,*", + "CDEF:meL$lvar=me$lvar,$swidth,-", + "CDEF:meH$lvar=me$lvar,0,*,$swidth,2,*,+", + "AREA:meL$lvar", + "STACK:meH$lvar$lc{$loss}[1]:$lc{$loss}[0]" + # "LINE2:me$lvar$lc{$loss}[1]:$lc{$loss}[0]" + ); + $last = $loss; } - push @median, ( "GPRINT:ploss:AVERAGE: avg pkg loss\\: %.2lf %%\\l" ); -# map {print "$_<br/>"} @median; - }; + push @median, ( "COMMENT:\\l", + "GPRINT:ploss:AVERAGE:Packet Loss\\: %.2lf %% average", + "GPRINT:ploss:MAX:%.2lf %% maximum", + "GPRINT:ploss:LAST:%.2lf %% current\\l" + ); + # if we have uptime draw a colorful background or the graph showing the uptime - my $cdir=$cfg->{General}{datadir}."/".(join "/", @dirs)."/"; + my $cdir=dyndir($cfg)."/".(join "/", @dirs)."/"; if (-f "$cdir/${file}.adr") { - @upsmoke = (); - @upargs = ('COMMENT:Link Up: ', - "DEF:uptime=${rrd}:uptime:AVERAGE", - "CDEF:duptime=uptime,86400,/", - 'GPRINT:duptime:LAST: %0.1lf days ('); - my %upt; - if ( defined $cfg->{Presentation}{detail}{uptime_colors}{_table} ) { - for (@{$cfg->{Presentation}{detail}{uptime_colors}{_table}}) { - my ($num,$col,$txt) = @{$_}; - $upt{$num} = [ $txt, "#".$col]; - } - } else { - %upt = ( 3600 => ['<1h', '#FFD3D3'], - 2*3600 => ['<2h', '#FFE4C7'], - 6*3600 => ['<6h', '#FFF9BA'], - 12*3600 => ['<12h','#F3FFC0'], - 24*3600 => ['<1d', '#E1FFCC'], - 7*24*3600 => ['<1w', '#BBFFCB'], - 30*24*3600 => ['<1m', '#BAFFF5'], - '1e100' => ['>1m', '#DAECFF'] - ); - } - my $lastup = 0; - foreach my $uptime (sort {$a <=> $b} keys %upt){ - push @upargs, - ( - "CDEF:up$uptime=uptime,$lastup,GE,uptime,$uptime,LE,*,INF,UNKN,IF", - "AREA:up$uptime$upt{$uptime}[1]:$upt{$uptime}[0]" - ); - push @upsmoke, - ( - "CDEF:ups$uptime=uptime,$lastup,GE,uptime,$uptime,LE,*,cp2,UNKN,IF", - "AREA:ups$uptime$upt{$uptime}[1]" + @upsmoke = (); + @upargs = ("COMMENT:Link Up${BS}: ", + "DEF:uptime=${rrd}:uptime:AVERAGE", + "CDEF:duptime=uptime,86400,/", + 'GPRINT:duptime:LAST: %0.1lf days ('); + my $lastup = 0; + foreach my $uptime (sort {$a <=> $b} keys %upt){ + push @upargs, + ( + "CDEF:up$uptime=uptime,$lastup,GE,uptime,$uptime,LE,*,INF,UNKN,IF", + "AREA:up$uptime$upt{$uptime}[1]:$upt{$uptime}[0]" + ); + push @upsmoke, + ( + "CDEF:ups$uptime=uptime,$lastup,GE,uptime,$uptime,LE,*,cp2,UNKN,IF", + "AREA:ups$uptime$upt{$uptime}[1]" ); - $lastup=$uptime; - } - - push @upargs, 'COMMENT:)\l'; -# map {print "$_<br/>"} @upargs; - }; + $lastup=$uptime; + } + + push @upargs, 'COMMENT:)\l'; + # map {print "$_<br/>"} @upargs; + }; my @log = (); push @log, "--logarithmic" if $cfg->{Presentation}{detail}{logarithmic} and - $cfg->{Presentation}{detail}{logarithmic} eq 'yes'; - + $cfg->{Presentation}{detail}{logarithmic} eq 'yes'; + my @lazy =(); - @lazy = ('--lazy') if $lasthight{$start} and $lasthight{$start} == $max->{$start}; - my ($graphret,$xs,$ys) = RRDs::graph - ($cfg->{General}{imgcache}.$dir."/${file}_last_${start}.png", + @lazy = ('--lazy') if $mode eq 's' and $lasthight{$start} and $lasthight{$start} == $max->{$start}; + $desc = "Navigator Graph" if $mode eq 'n'; + my $timer_start = time(); + my @task = + ("${imgbase}_${end}_${start}.png", @lazy, - '--start','-'.$start, + '--start',( $mode eq 's' ? '-'.$start : $start), + ($end ne 'last' ? ('--end',$end) : ()), '--height',$cfg->{Presentation}{detail}{height}, '--width',,$cfg->{Presentation}{detail}{width}, '--title',$desc, - '--rigid', - '--upper-limit', $max->{$start}, + '--rigid','--upper-limit', $max->{$start}, @log, '--lower-limit',(@log ? ($max->{$start} > 0.01) ? '0.001' : '0.0001' : '0'), '--vertical-label',"Seconds", @@ -824,8 +918,6 @@ sub get_detail ($$$$){ @$smoke, @upsmoke, # draw the rest of the uptime bg color @median, -# 'LINE3:median#ff0000:Median RTT in grey '.$cfg->{Database}{pings}.' pings sorted by RTT', -# 'LINE1:median#ff8080', # Gray background for times when no data was collected, so they can # be distinguished from network being down. ( $cfg->{Presentation}{detail}{nodata_color} ? ( @@ -834,14 +926,39 @@ sub get_detail ($$$$){ ()), 'HRULE:0#000000', 'COMMENT:\s', - "COMMENT:Probe: $pings $ProbeDesc every $step seconds", + "COMMENT:Probe${BS}: $pings $ProbeDesc every $step seconds", 'COMMENT:created on '.$date.'\j' ); + + my ($graphret,$xs,$ys) = RRDs::graph @task; my $ERROR = RRDs::error(); - $page .= "<div>". - ( $ERROR || - "<IMG BORDER=\"0\" WIDTH=\"$xs\" HEIGHT=\"$ys\" ". - "SRC=\"".$cfg->{General}{imgurl}.$dir."/${file}_last_${start}.png\">" )."</div>"; + if ($mode eq 'n'){ + $page .= "<div>"; + $page .= ( $ERROR || qq|<IMG BORDER="0" WIDTH="$xs" HEIGHT="$ys" SRC="${imghref}_${end}_${start}.png">| ); + $page .= "</div>"; + $page .= $q->start_form(-method=>'GET') + . "<p>Time range: " + . $q->textfield(-name=>'start',-default=>$startstr) + . " to ".$q->textfield(-name=>'end',-default=>$endstr) + . $q->hidden(-name=>'target' ) + . $q->hidden(-name=>'displaymode',-default=>$mode ) + . " " + . $q->submit(-name=>'Generate!') + . "</p>" + . $q->end_form(); + } else { + $startstr =~ s/\s/%20/g; + $endstr =~ s/\s/%20/g; + $page .= "<div>"; +# $page .= (time-$timer_start)."<br/>"; +# $page .= join " ",map {"'$_'"} @task; + $page .= "<br/>"; + $page .= ( $ERROR || + qq{<a href="?displaymode=n;start=$startstr;end=now;}."target=".$q->param('target').'">' + . qq{<IMG BORDER="0" WIDTH="$xs" HEIGHT="$ys" SRC="${imghref}_${end}_${start}.png">}."</a>" ); + $page .= "</div>"; + + } } return $page; @@ -918,13 +1035,16 @@ sub update_rrds($$$$$) { my $justthisprobe = shift; # if defined, update only the targets probed by this probe my $probe = $tree->{probe}; - my $probeobj = $probes->{$probe}; foreach my $prop (keys %{$tree}) { if (ref $tree->{$prop} eq 'HASH'){ update_rrds $cfg, $probes, $tree->{$prop}, $name."/$prop", $justthisprobe; } - next if defined $justthisprobe and $probe ne $justthisprobe; + # if we are looking down a branche where no probe propperty is set there is not sense + # in further exploring it + next unless defined $probe; + next if defined $justthisprobe and $probe ne $justthisprobe; + my $probeobj = $probes->{$probe}; if ($prop eq 'host' and check_filter($cfg,$name)) { #print "update $name\n"; my $updatestring = $probeobj->rrdupdate_string($tree); @@ -1383,7 +1503,7 @@ DOC # if there is a subprobe, the top-level section # of this probe turns into a template, and we # need to delete its _mandatory list. - # Note that ISG::ParseConfig does mandatory checking + # Note that Config::Grammar does mandatory checking # after the whole config tree is read, so we can fiddle # here with "_mandatory" all we want. # see 1.3 above @@ -1446,7 +1566,7 @@ DOC }, }; # $PROBES - my $parser = ISG::ParseConfig->new + my $parser = Config::Grammar->new ( { _sections => [ qw(General Database Presentation Probes Alerts Targets) ], @@ -1457,9 +1577,9 @@ DOC General configuration values valid for the whole SmokePing setup. DOC _vars => - [ qw(owner imgcache imgurl datadir pagedir piddir sendmail offset + [ qw(owner imgcache imgurl datadir dyndir pagedir piddir sendmail offset smokemail cgiurl mailhost contact netsnpp - syslogfacility syslogpriority concurrentprobes changeprocessnames) ], + syslogfacility syslogpriority concurrentprobes changeprocessnames tmail) ], _mandatory => [ qw(owner imgcache imgurl datadir piddir smokemail cgiurl contact) ], @@ -1527,7 +1647,16 @@ DOC The directory where SmokePing can keep its rrd files. DOC }, + dyndir => + { + %$DIRCHECK_SUB, + _doc => <<DOC, +The base directory where SmokePing keeps the files related to the DYNAMIC function. +This directory must be writeable by the WWW server. +If this variable is not specified, the value of C<datadir> will be used instead. +DOC + }, piddir => { %$DIRCHECK_SUB, @@ -1618,6 +1747,13 @@ be appended to the process name as '[probe]', eg. '/usr/bin/smokeping If 'concurrentprobes' is not set to 'yes', this variable has no effect. DOC }, + tmail => + { + %$FILECHECK_SUB, + _doc => <<DOC, +Path to your tSmoke HTML mail template file. See the tSmoke documentation for details. +DOC + } }, Database => { @@ -2036,7 +2172,7 @@ let the pattern match: >10%,*10*,>10% -will fire if more than 10% of the packets have been losst twice over the +will fire if more than 10% of the packets have been lost at least twice over the last 10 samples. A complete example @@ -2278,6 +2414,7 @@ sub daemonize_me ($) { sub initialize_cgilog (){ $use_cgilog = 1; + CGI::Carp::set_progname($0 . " [client " . ($ENV{REMOTE_ADDR}||"(unknown)") . "]"); $logging=1; } @@ -2305,7 +2442,7 @@ sub daemonize_me ($) { sub do_cgilog ($){ my $str = shift; print "<p>" , $str, "</p>\n"; - print STDERR $str,"\n"; # for the webserver log + warn $str, "\n"; # for the webserver log } sub do_debuglog ($){ @@ -2359,6 +2496,7 @@ sub load_cfg ($) { sub makepod ($){ my $parser = shift; my $e='='; + my $a='@'; my $retval = <<POD; ${e}head1 NAME @@ -2374,7 +2512,7 @@ The contents of this manual is generated directly from the configuration file parser. The Parser for the Configuration file is written using David Schweikers -ParseConfig module. Read all about it in L<ISG::ParseConfig>. +Config::Grammar module. Read all about it in L<Config::Grammar>. The Configuration file has a tree-like structure with section headings at various levels. It also contains variable assignments and tables. @@ -2384,7 +2522,29 @@ for simple configuration examples. ${e}head1 REFERENCE -The text below describes the syntax of the SmokePing configuration file. +${e}head2 GENERAL SYNTAX + +The text below describes the general syntax of the SmokePing configuration file. +It was copied from the Config::Grammar documentation. + +'#' denotes a comment up to the end-of-line, empty lines are allowed and space +at the beginning and end of lines is trimmed. + +'\\' at the end of the line marks a continued line on the next line. A single +space will be inserted between the concatenated lines. + +'${a}include filename' is used to include another file. + +'${a}define a some value' will replace all occurences of 'a' in the following text +with 'some value'. + +Fields in tables that contain white space can be enclosed in either C<'> or C<">. +Whitespace can also be escaped with C<\\>. Quotes inside quotes are allowed but must +be escaped with a backslash as well. + +${e}head2 SPECIFIC SYNTAX + +The text below describes the specific syntax of the SmokePing configuration file. POD @@ -2427,14 +2587,21 @@ sub cgi ($) { umask 022; load_cfg shift; my $q=new CGI; - print $q->header(-type=>'text/html', + initialize_cgilog(); + if ($q->param(-name=>'secret') && $q->param(-name=>'target') ) { + my $ret = update_dynaddr $cfg,$q; + if (defined $ret and $ret ne "") { + print $q->header(-status => "404 Not Found"); + do_cgilog("Updating DYNAMIC address failed: $ret"); + } else { + print $q->header; # no HTML output on success + } + } else { + print $q->header(-type=>'text/html', -expires=>'+'.($cfg->{Database}{step}).'s', -charset=> ( $cfg->{Presentation}{charset} || 'iso-8859-15') ); - if ($q->param(-name=>'secret') && $q->param(-name=>'target') ) { - update_dynaddr $cfg,$q; - } else { - display_webpage $cfg,$q; + display_webpage $cfg,$q; } } |