diff options
-rw-r--r-- | doc/smokeping_master_slave.pod | 6 | ||||
-rw-r--r-- | etc/config.dist | 22 | ||||
-rw-r--r-- | lib/Smokeping.pm | 54 | ||||
-rw-r--r-- | lib/Smokeping/Master.pm | 71 | ||||
-rw-r--r-- | lib/Smokeping/Slave.pm | 128 |
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; |