summaryrefslogtreecommitdiffstats
path: root/lib/Smokeping/probes/base.pm
diff options
context:
space:
mode:
authorNiko Tyni <ntyni@iki.fi>2005-02-13 20:23:04 +0100
committerNiko Tyni <ntyni@iki.fi>2005-02-13 20:23:04 +0100
commit6d76521656e91daa160bc8019828f1b68d7aa5dc (patch)
treeaaa27615a0702942fa1606d9a5c89f0a3547467c /lib/Smokeping/probes/base.pm
parent6dba1afbe4b475a7d34f5ef867b7b37291cd1484 (diff)
downloadsmokeping-6d76521656e91daa160bc8019828f1b68d7aa5dc.tar.gz
smokeping-6d76521656e91daa160bc8019828f1b68d7aa5dc.tar.xz
Moved probes, matchers and ciscoRttMonMIB modules to lib/Smokeping.
Diffstat (limited to 'lib/Smokeping/probes/base.pm')
-rw-r--r--lib/Smokeping/probes/base.pm400
1 files changed, 400 insertions, 0 deletions
diff --git a/lib/Smokeping/probes/base.pm b/lib/Smokeping/probes/base.pm
new file mode 100644
index 0000000..0309550
--- /dev/null
+++ b/lib/Smokeping/probes/base.pm
@@ -0,0 +1,400 @@
+package Smokeping::probes::base;
+
+=head1 301 Moved Permanently
+
+This is a Smokeping probe module. Please use the command
+
+C<smokeping -man Smokeping::probes::base>
+
+to view the documentation or the command
+
+C<smokeping -makepod Smokeping::probes::base>
+
+to generate the POD document.
+
+=cut
+
+use vars qw($VERSION);
+use Carp;
+use lib qw(..);
+use Smokeping;
+
+$VERSION = 1.0;
+
+use strict;
+
+sub pod_hash {
+ return {
+ name => <<DOC,
+Smokeping::probes::base - Base Class for implementing SmokePing Probes
+DOC
+ overview => <<DOC,
+For the time being, please use the Smokeping::probes::FPing for
+inspiration when implementing your own probes.
+DOC
+ authors => <<'DOC',
+Tobias Oetiker <tobi@oetiker.ch>
+DOC
+ };
+}
+
+sub pod {
+ my $class = shift;
+ my $pod = "";
+ my $podhash = $class->pod_hash;
+ $podhash->{synopsys} = $class->pod_synopsys;
+ $podhash->{variables} = $class->pod_variables;
+ for my $what (qw(name overview synopsys description variables authors notes bugs see_also)) {
+ my $contents = $podhash->{$what};
+ next if not defined $contents or $contents eq "";
+ $pod .= "=head1 " . uc $what . "\n\n";
+ $pod .= $contents;
+ chomp $pod;
+ $pod .= "\n\n";
+ }
+ $pod .= "=cut";
+ return $pod;
+}
+
+sub new($$)
+{
+ my $this = shift;
+ my $class = ref($this) || $this;
+ my $self = { properties => shift, cfg => shift,
+ name => shift,
+ targets => {}, rtts => {}, addrlookup => {}};
+ bless $self, $class;
+ return $self;
+}
+
+sub add($$)
+{
+ my $self = shift;
+ my $tree = shift;
+
+ $self->{targets}{$tree} = shift;
+}
+
+sub ping($)
+{
+ croak "this must be overridden by the subclass";
+}
+
+sub round ($) {
+ return sprintf "%.0f", $_[0];
+}
+
+sub ProbeDesc ($) {
+ return "Probe which does not overrivd the ProbeDesc methode";
+}
+
+sub rrdupdate_string($$)
+{ my $self = shift;
+ my $tree = shift;
+# print "$tree -> ", join ",", @{$self->{rtts}{$tree}};print "\n";
+ # skip invalid addresses
+ my $pings = $self->_pings($tree);
+ return "U:${pings}:".(join ":", map {"U"} 1..($pings+1))
+ unless defined $self->{rtts}{$tree} and @{$self->{rtts}{$tree}} > 0;
+ my $entries = scalar @{$self->{rtts}{$tree}};
+ my @times = @{$self->{rtts}{$tree}};
+ my $loss = $pings - $entries;
+ my $median = $times[int($entries/2)] || 'U';
+ # shift the data into the middle of the times array
+ my $lowerloss = int($loss/2);
+ my $upperloss = $loss - $lowerloss;
+ @times = ((map {'U'} 1..$lowerloss),@times, (map {'U'} 1..$upperloss));
+ my $age;
+ if ( -f $self->{targets}{$tree}.".adr" ) {
+ $age = time - (stat($self->{targets}{$tree}.".adr"))[9];
+ } else {
+ $age = 'U';
+ }
+ if ( $entries == 0 ){
+ $age = 'U';
+ $loss = 'U';
+ if ( -f $self->{targets}{$tree}.".adr"
+ and not -f $self->{targets}{$tree}.".snmp" ){
+ unlink $self->{targets}{$tree}.".adr";
+ }
+ } ;
+ return "${age}:${loss}:${median}:".(join ":", @times);
+}
+
+sub addresses($)
+{
+ my $self = shift;
+ my $addresses = [];
+ $self->{addrlookup} = {};
+ foreach my $tree (keys %{$self->{targets}}){
+ my $target = $self->{targets}{$tree};
+ if ($target =~ m|/|) {
+ if ( open D, "<$target.adr" ) {
+ my $ip;
+ chomp($ip = <D>);
+ close D;
+
+ if ( open D, "<$target.snmp" ) {
+ my $snmp = <D>;
+ chomp($snmp);
+ if ($snmp ne Smokeping::snmpget_ident $ip) {
+ # something fishy snmp properties do not match, skip this address
+ next;
+ }
+ close D;
+ }
+ $target = $ip;
+ } else {
+ # can't read address file skip
+ next;
+ }
+ }
+ $self->{addrlookup}{$target} = ()
+ unless defined $self->{addrlookup}{$target};
+ push @{$self->{addrlookup}{$target}}, $tree;
+ push @{$addresses}, $target;
+ };
+ return $addresses;
+}
+
+sub debug {
+ my $self = shift;
+ my $newval = shift;
+ $self->{debug} = $newval if defined $newval;
+ return $self->{debug};
+}
+
+sub do_debug {
+ my $self = shift;
+ return unless $self->debug;
+ $self->do_log(@_);
+}
+
+sub do_fatal {
+ my $self = shift;
+ $self->do_log("Fatal:", @_);
+ croak(@_);
+}
+
+sub do_log {
+ my $self = shift;
+ Smokeping::do_log("$self->{name}:", @_);
+}
+
+sub report {
+ my $self = shift;
+ my $count = $self->target_count;
+ my $offset = $self->offset_in_seconds;
+ my $step = $self->step;
+ $self->do_log("probing $count targets with step $step s and offset $offset s.");
+}
+
+sub step {
+ my $self = shift;
+ my $rv = $self->{cfg}{Database}{step};
+ unless (defined $self->{cfg}{General}{concurrentprobes}
+ and $self->{cfg}{General}{concurrentprobes} eq 'no') {
+ $rv = $self->{properties}{step} if defined $self->{properties}{step};
+ }
+ return $rv;
+}
+
+sub offset {
+ my $self = shift;
+ my $rv = $self->{cfg}{General}{offset};
+ unless (defined $self->{cfg}{General}{concurrentprobes}
+ and $self->{cfg}{General}{concurrentprobes} eq 'no') {
+ $rv = $self->{properties}{offset} if defined $self->{properties}{offset};
+ }
+ return $rv;
+}
+
+sub offset_in_seconds {
+ # returns the offset in seconds rather than as a percentage
+ # this is filled in from the initialization in Smokeping::main
+ my $self = shift;
+ my $newval = shift;
+ $self->{offset_in_seconds} = $newval if defined $newval;
+ return $self->{offset_in_seconds};
+}
+
+# the "public" method that takes a "target" argument is used by the probes
+# the "private" method that takes a "tree" argument is used by Smokeping.pm
+# there's no difference between them here, but we have to provide both
+
+sub pings {
+ my $self = shift;
+ my $target = shift;
+ # $target is not used; basefork.pm overrides this method to provide a target-specific parameter
+ my $rv = $self->{cfg}{Database}{pings};
+ $rv = $self->{properties}{pings} if defined $self->{properties}{pings};
+ return $rv;
+}
+
+
+sub _pings {
+ my $self = shift;
+ my $tree = shift;
+ # $tree is not used; basefork.pm overrides this method to provide a target-specific parameter
+ my $rv = $self->{cfg}{Database}{pings};
+ $rv = $self->{properties}{pings} if defined $self->{properties}{pings};
+ return $rv;
+}
+
+sub target_count {
+ my $self = shift;
+ return scalar keys %{$self->{targets}};
+}
+
+sub probevars {
+ return {
+ step => {
+ _re => '\d+',
+ _example => 300,
+ _doc => <<DOC,
+Duration of the base interval that this probe should use, if different
+from the one specified in the 'Database' section. Note that the step in
+the RRD files is fixed when they are originally generated, and if you
+change the step parameter afterwards, you'll have to delete the old RRD
+files or somehow convert them. (This variable is only applicable if
+the variable 'concurrentprobes' is set in the 'General' section.)
+DOC
+ },
+ offset => {
+ _re => '(\d+%|random)',
+ _re_error =>
+ "Use offset either in % of operation interval or 'random'",
+ _example => '50%',
+ _doc => <<DOC,
+If you run many probes concurrently you may want to prevent them from
+hitting your network all at the same time. Using the probe-specific
+offset parameter you can change the point in time when each probe will
+be run. Offset is specified in % of total interval, or alternatively as
+'random', and the offset from the 'General' section is used if nothing
+is specified here. Note that this does NOT influence the rrds itself,
+it is just a matter of when data acqusition is initiated.
+(This variable is only applicable if the variable 'concurrentprobes' is set
+in the 'General' section.)
+DOC
+ },
+ pings => {
+ _re => '\d+',
+ _example => 20,
+ _doc => <<DOC,
+How many pings should be sent to each target, if different from the global
+value specified in the Database section. Note that the number of pings in
+the RRD files is fixed when they are originally generated, and if you
+change this parameter afterwards, you'll have to delete the old RRD
+files or somehow convert them.
+DOC
+ },
+ _mandatory => [],
+ };
+}
+
+sub targetvars {
+ return {_mandatory => []};
+}
+
+# a helper method that combines two var hash references
+# and joins their '_mandatory' lists.
+sub _makevars {
+ my ($class, $from, $to) = @_;
+ for (keys %$from) {
+ if ($_ eq '_mandatory') {
+ push @{$to->{_mandatory}}, @{$from->{$_}};
+ next;
+ }
+ $to->{$_} = $from->{$_};
+ }
+ return $to;
+}
+
+sub pod_synopsys {
+ my $class = shift;
+ my $classname = ref $class||$class;
+ $classname =~ s/^Smokeping::probes:://;
+
+ my $probevars = $class->probevars;
+ my $targetvars = $class->targetvars;
+ my $pod = <<DOC;
+ *** Probes ***
+
+ +$classname
+
+DOC
+ $pod .= $class->_pod_synopsys($probevars);
+ my $targetpod = $class->_pod_synopsys($targetvars);
+ $pod .= "\n # The following variables can be overridden in each target section\n$targetpod"
+ if defined $targetpod and $targetpod ne "";
+ $pod .= <<DOC;
+
+ # [...]
+
+ *** Targets ***
+
+ probe = $classname # if this should be the default probe
+
+ # [...]
+
+ + mytarget
+ # probe = $classname # if the default probe is something else
+ host = my.host
+DOC
+ $pod .= $targetpod
+ if defined $targetpod and $targetpod ne "";
+
+ return $pod;
+}
+
+# synopsys for one hash ref
+sub _pod_synopsys {
+ my $class = shift;
+ my $vars = shift;
+ my %mandatory;
+ $mandatory{$_} = 1 for (@{$vars->{_mandatory}});
+ my $pod = "";
+ for (sort keys %$vars) {
+ next if /^_mandatory$/;
+ my $val = $vars->{$_}{_example};
+ $val = $vars->{$_}{_default}
+ if exists $vars->{$_}{_default}
+ and not defined $val;
+ $pod .= " $_ = $val";
+ $pod .= " # mandatory" if $mandatory{$_};
+ $pod .= "\n";
+ }
+ return $pod;
+}
+
+sub pod_variables {
+ my $class = shift;
+ my $probevars = $class->probevars;
+ my $pod = "Supported probe-specific variables:\n\n";
+ $pod .= $class->_pod_variables($probevars);
+ return $pod;
+}
+
+sub _pod_variables {
+ my $class = shift;
+ my $vars = shift;
+ my $pod = "=over\n\n";
+ my %mandatory;
+ $mandatory{$_} = 1 for (@{$vars->{_mandatory}});
+ for (sort keys %$vars) {
+ next if /^_mandatory$/;
+ $pod .= "=item $_\n\n";
+ $pod .= $vars->{$_}{_doc};
+ chomp $pod;
+ $pod .= "\n\n";
+ $pod .= "Example value: " . $vars->{$_}{_example} . "\n\n"
+ if exists $vars->{$_}{_example};
+ $pod .= "Default value: " . $vars->{$_}{_default} . "\n\n"
+ if exists $vars->{$_}{_default};
+ $pod .= "This setting is mandatory.\n\n"
+ if $mandatory{$_};
+ }
+ $pod .= "=back\n\n";
+ return $pod;
+}
+1;