summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/smokeping_master_slave.pod6
-rw-r--r--etc/config.dist22
-rw-r--r--lib/Smokeping.pm54
-rw-r--r--lib/Smokeping/Master.pm71
-rw-r--r--lib/Smokeping/Slave.pm128
5 files changed, 201 insertions, 80 deletions
diff --git a/doc/smokeping_master_slave.pod b/doc/smokeping_master_slave.pod
index e479909..967a976 100644
--- a/doc/smokeping_master_slave.pod
+++ b/doc/smokeping_master_slave.pod
@@ -95,9 +95,9 @@ that it runs in slave-mode and its secret. The secet is stored in a file for
optimal protection. By default the persitant data cache will be located in
F</tmp/smokeping.$USER.cache>.
- ./smokeping --master=http://smokeping/smokeping.cgi \
- --cache=/var/smokeping/cache.file \
- --secret=/var/smokeping/secret.txt
+ ./smokeping --master-url=http://smokeping/smokeping.cgi \
+ --cache-dir=/var/smokeping/cache.file \
+ --shared-secret=/var/smokeping/secret.txt
=head1 COPYRIGHT
diff --git a/etc/config.dist b/etc/config.dist
index fbb0d9d..0a0910b 100644
--- a/etc/config.dist
+++ b/etc/config.dist
@@ -10,11 +10,11 @@ mailhost = smtp.mailhost.abc
sendmail = /usr/lib/sendmail
imgcache = /home/oetiker/public_html/.simg
imgurl = ../.simg
-datadir = /home/oetiker/data/projects/AADJ-smokeping/dist/var
-piddir = /home/oetiker/data/projects/AADJ-smokeping/dist/var
-cgiurl = http://people.ee.ethz.ch/~oetiker/smokeping/smokeping.cgi
-smokemail = /home/oetiker/data/projects/AADJ-smokeping/dist/etc/smokemail.dist
-tmail = /home/oetiker/data/projects/AADJ-smokeping/dist/etc/tmail.dist
+datadir = /tmp/smokeping/data
+piddir = /tmp/smokeping/var
+cgiurl = http://tobi.oetiker.ch/smokeping/smokeping.cgi
+smokemail = /home/oetiker/checkouts/smokeping/trunk/software/etc/smokemail.dist
+tmail = /home/oetiker/checkouts/smokeping/trunk/software/etc/tmail.dist
# specify this to get syslog logging
syslogfacility = local0
# each probe is now run in its own process
@@ -66,7 +66,7 @@ AVERAGE 0.5 144 720
*** Presentation ***
-template = /home/oetiker/data/projects/AADJ-smokeping/dist/etc/basepage.html.dist
+template = /home/oetiker/checkouts/smokeping/trunk/software/etc/basepage.html.dist
+ overview
@@ -89,7 +89,14 @@ unison_tolerance = 2
+ FPing
-binary = /usr/sepp/bin/fping
+binary = /usr/sbin/fping
+
+*** Slaves ***
+secrets=/home/oetiker/checkouts/smokeping/trunk/software/etc/smokeping_secrets.dist
++mipsrv01
+name=mipsrv01
+++override
+Probes.FPing.binary=/usr/bin/fping
*** Targets ***
@@ -115,6 +122,7 @@ title =European Connectivity
menu = Switzerland
title =Swiss Connectivity
alerts = bigloss,someloss,startloss
+slaves = mipsrv01 johan
++++ SBB
diff --git a/lib/Smokeping.pm b/lib/Smokeping.pm
index 55c1c5b..f6bcdd2 100644
--- a/lib/Smokeping.pm
+++ b/lib/Smokeping.pm
@@ -372,12 +372,37 @@ sub check_filter ($$) {
return 1;
}
+sub add_targets ($$$$);
+sub add_targets ($$$$){
+ my $cfg = shift;
+ my $probes = shift;
+ my $tree = shift;
+ my $name = shift;
+ die "Error: Invalid Probe: $tree->{probe}" unless defined $probes->{$tree->{probe}};
+ my $probeobj = $probes->{$tree->{probe}};
+ foreach my $prop (keys %{$tree}) {
+ if (ref $tree->{$prop} eq 'HASH'){
+ add_targets $cfg, $probes, $tree->{$prop}, "$name/$prop";
+ }
+ if ($prop eq 'host' and check_filter($cfg,$name)) {
+ if($tree->{host} =~ /^DYNAMIC/) {
+ $probeobj->add($tree,$name);
+ } else {
+ $probeobj->add($tree,$tree->{host});
+ }
+ }
+ }
+}
+
+
sub init_target_tree ($$$$); # predeclare recursive subs
sub init_target_tree ($$$$) {
my $cfg = shift;
my $probes = shift;
my $tree = shift;
my $name = shift;
+ die "Error: Invalid Probe: $tree->{probe}" unless defined $probes->{$tree->{probe}};
+ my $probeobj = $probes->{$tree->{probe}};
if ($tree->{alerts}){
die "ERROR: no Alerts section\n"
@@ -404,15 +429,8 @@ sub init_target_tree ($$$$) {
}
if ($prop eq 'host' and check_filter($cfg,$name)) {
# print "init $name\n";
- die "Error: Invalid Probe: $tree->{probe}" unless defined $probes->{$tree->{probe}};
- my $probeobj = $probes->{$tree->{probe}};
my $step = $probeobj->step();
# we have to do the add before calling the _pings method, it won't work otherwise
- if($tree->{$prop} =~ /^DYNAMIC/) {
- $probeobj->add($tree,$name);
- } else {
- $probeobj->add($tree,$tree->{$prop});
- }
my $pings = $probeobj->_pings($tree);
my @create =
@@ -3089,20 +3107,21 @@ sub load_cfg ($;$) {
if (not defined $cfg or not defined $probes or $cfg->{__last} < $cfmod ){
$cfg = undef;
my $parser = get_parser;
- $cfg = get_config $parser, $cfgfile;
- if (defined $cfg->{Presentation}{charts}){
- require Storable;
- die "ERROR: Could not load Storable Support. This is required for the Charts feature - $@\n" if $@;
+ $cfg = get_config $parser, $cfgfile;
+ if (defined $cfg->{Presentation}{charts}){
+ require Storable;
+ die "ERROR: Could not load Storable Support. This is required for the Charts feature - $@\n" if $@;
load_sorters $cfg->{Presentation}{charts};
}
$cfg->{__parser} = $parser;
- $cfg->{__last} = $cfmod;
- $cfg->{__cfgfile} = $cfgfile;
+ $cfg->{__last} = $cfmod;
+ $cfg->{__cfgfile} = $cfgfile;
$probes = undef;
- $probes = load_probes $cfg;
- $cfg->{__probes} = $probes;
- return if $noinit;
- init_alerts $cfg if $cfg->{Alerts};
+ $probes = load_probes $cfg;
+ $cfg->{__probes} = $probes;
+ return if $noinit;
+ init_alerts $cfg if $cfg->{Alerts};
+ add_targets $cfg, $probes, $cfg->{Targets}, $cfg->{General}{datadir};
init_target_tree $cfg, $probes, $cfg->{Targets}, $cfg->{General}{datadir};
} else {
do_log("Config file unmodified, skipping reload") unless $cgimode;
@@ -3446,6 +3465,7 @@ sub main (;$) {
exit 0;
};
load_cfg $cfgfile;
+
if(defined $opt{'static-pages'}) { makestaticpages $cfg, $opt{'static-pages'}; exit 0 };
if($opt{email}) { enable_dynamic $cfg, $cfg->{Targets},"",""; exit 0 };
if($opt{restart}) { kill_smoke $cfg->{General}{piddir}."/smokeping.pid", SIGINT;};
diff --git a/lib/Smokeping/Master.pm b/lib/Smokeping/Master.pm
index d6d4caa..1b763a7 100644
--- a/lib/Smokeping/Master.pm
+++ b/lib/Smokeping/Master.pm
@@ -1,7 +1,10 @@
# -*- perl -*-
package Smokeping::Master;
use HTTP::Request;
-
+use Data::Dumper;
+use Storable qw(dclone nfreeze);
+use strict;
+use warnings;
=head1 NAME
@@ -23,32 +26,54 @@ file will be patched for the slave.
=cut
-sub extract_config($$){
- my $cfg = shift;
- my $slave = shift;
-}
-
-=head3 poll_slave(cfg,slave)
-
-Get latest measurement results from the slave
-
-=cut
-
-sub poll_slave($$){
- my $cfg = shift;
+sub get_targets;
+sub get_targets {
+ my $trg = shift;
my $slave = shift;
+ my %return;
+ my $ok;
+ foreach my $key (keys %{$trg}){
+ # dynamic hosts can only be queried from the
+ # master
+ next if $key eq 'host' and $trg->{$key} eq 'DYNAMIC';
+ next if $key eq 'host' and not ( defined $trg->{slaves} and $trg->{slaves} =~ /\b${slave}\b/);
+ if (ref $trg->{$key} eq 'HASH'){
+ $return{$key} = get_targets ($trg->{$key},$slave);
+ $ok = 1 if defined $return{$key};
+ } else {
+ $ok = 1 if $key eq 'host';
+ $return{$key} = $trg->{$key};
+ }
+ }
+ return ($ok ? \%return : undef);
}
-
-
-=head3 push_config(cfg,slave)
-
-Upload new config information to the slave if the poll result shows that it needs an update.
-
-=cut
-
-sub push_config ($$){
+
+
+
+sub extract_config {
my $cfg = shift;
my $slave = shift;
+ # get relevant Targets
+ my %slave_config;
+ $slave_config{Database} = dclone $cfg->{Database};
+ $slave_config{General} = dclone $cfg->{General};
+ $slave_config{Probes} = dclone $cfg->{Probes};
+ $slave_config{Targets} = get_targets($cfg->{Targets},$slave);
+ $slave_config{__last} = $cfg->{__last};
+ if ($cfg->{Slaves} and $cfg->{Slaves}{$slave} and $cfg->{Slaves}{$slave}{override}){
+ for my $override (keys %{$cfg->{Slaves}{$slave}{override}}){
+ my $node = \%slave_config;
+ my @keys = split /\./, $override;
+ my $last_key = pop @keys;
+ for my $key (@keys){
+ $node->{$key} = {}
+ unless $node->{$key} and ref $node->{$key} eq 'HASH';
+ $node = $node->{$key};
+ }
+ $node->{$last_key} = $cfg->{Slaves}{$slave}{override}{$override};
+ }
+ }
+ return nfreesze \%slave_config;
}
1;
diff --git a/lib/Smokeping/Slave.pm b/lib/Smokeping/Slave.pm
index 42c71c5..b02511b 100644
--- a/lib/Smokeping/Slave.pm
+++ b/lib/Smokeping/Slave.pm
@@ -1,55 +1,123 @@
# -*- perl -*-
package Smokeping::Slave;
-use HTTP::Daemon;
-use HTTP::Status;
+use warnings;
+use strict;
+use Data::Dumper;
+use Storable qw(nstore nretreive);
+use Digest::MD5 qw(md5_ base64);
+use LWP::UserAgent;
+use Smokeping;
+
=head1 NAME
-Smokeping::Slave - Slave Functionality for Smokeping
+Smokeping::Slave - Slave functionality for Smokeping
=head1 OVERVIEW
-This module handles all special functionality required by smokeping running
-in slave mode.
+The Module inmplements the functionality required to run in slave mode.
=head2 IMPLEMENTATION
-=head3 slave_cfg=extract_config(cfg,slave)
+=head3 submit_results
-Extract the relevant configuration information for the selected slave. The
-configuration will only contain the information that is relevant for the
-slave. Any parameters overwritten in the B<Slaves> section of the configuration
-file will be patched for the slave.
+In slave mode we just hit our targets and submit the results to the server.
+If we can not get to the server, we submit the results in the next round.
+The server in turn sends us new config information if it sees that ours is
+out of date.
=cut
-sub extract_config($$){
+sub get_results;
+sub get_results {
+ my $slave_cfg = shift;
+ my $cfg = shift;
+ my $probes = shift;
+ my $tree = shift;
+ my $name = shift;
+ my $justthisprobe = shift; # if defined, update only the targets probed by this probe
+ my $probe = $tree->{probe};
+ my $results = [];
+ foreach my $prop (keys %{$tree}) {
+ if (ref $tree->{$prop} eq 'HASH'){
+ my $subres = get_results $slave_cfg, $cfg, $probes, $tree->{$prop}, $name."/$prop", $justthisprobe;
+ push @{$results}, @{$subres};
+ }
+ next unless defined $probe;
+ next if defined $justthisprobe and $probe ne $justthisprobe;
+ my $probeobj = $probes->{$probe};
+ if ($prop eq 'host') {
+ #print "update $name\n";
+ my $updatestring = $probeobj->rrdupdate_string($tree);
+ my $pings = $probeobj->_pings($tree);
+ push @$results, [ $name, time, $updatestring];
+ }
+ }
+ return $results;
+}
+
+sub submit_results {
+ my $slave_cfg = shift;
my $cfg = shift;
- my $slave = shift;
+ my $myprobe = shift;
+ my $store = $slave_cfg->{cache_dir}."/data";
+ $store .= "_$myprobe" if $myprobe;
+ $store .= ".cache";
+ my $restore = nretrieve $store if -f $store;
+ my $data = get_results($slave_cfg, $cfg, $probes, $cfg->{Targets}, $cfg->{General}{datadir}, $myprobe);
+ push @$data, @$restore;
+ my $data_dump = Dumper $data;
+ my $ua = LWP::UserAgent->new(
+ agent => 'smokeping-slave/1.0',
+ from => $slave_cfg->{slave_name},
+ timeout => 10,
+ env_proxy => 1 );
+ my $response = $ua->post(
+ $slave_cfg->{master_url},
+ Content_Type => 'form-data',
+ Content => [
+ key => md5_base_64($slave_cfg->{shared_secret}.$data_dump)
+ data => $data_dump,
+ config_time => $cfg->{__last} || 0;
+ ],
+ );
+ if ($response->is_success){
+ my $data = $response->decoded_content;
+ my $key = $response->header('Key');
+ if (md5_base_64($slave_cfg->{shared_secret}.$data) ne $key){
+ warn "Warning: $slave_cfg->{master_url} sent data with wrong key";
+ return undef;
+ }
+ my $VAR1;
+ eval $data;
+ if (ref $VAR1 eq 'HASH'){
+ update_config $cfg,$VAR1;
+ }
+ } else {
+ # ok we have to store the result so that we can try again later
+ nstore $store;
+ warn $response->status_line();
+ }
+ return undef;
}
-=head3 expect_request(cfg)
+=head3 update_config
+
+Update the config information based on the latest input form the server.
=cut
-sub expect_request($){
+sub update_config {
my $cfg = shift;
- my $daemon = HTTP::Daemon->new or die "Creating HTTP daemon";
- print "Please contact me at: <URL:", $d->url, ">\n";
- while (my $c = $d->accept) {
- while (my $r = $c->get_request) {
- if ($r->method eq 'GET' and $r->url->path eq "/xyzzy") {
- # remember, this is *not* recommended practice :-)
- $c->send_file_response("/etc/passwd");
- }
- else {
- $c->send_error(RC_FORBIDDEN)
- }
- }
- $c->close;
- undef($c);
- }
-
+ my $data = shift;
+ $cfg->{General} = $data->{General};
+ $cfg->{Probes} = $data->{Probes};
+ $cfg->{Database} = $data->{Database};
+ $cfg->{Targets} = $data->{Targets};
+ $cfg->{__last} = $data->{__last};
+ $Smokeping::probes = Smokeping::load_probes $cfg;
+ $cfg->{__probes} = $probes;
+ add_targets $cfg, $probes, $cfg->{Targets}, $cfg->{General}{datadir};
}
1;