summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES1
-rw-r--r--Makefile8
-rw-r--r--doc/smokeping_upgrade.pod11
-rw-r--r--lib/Smokeping.pm10
-rw-r--r--lib/Smokeping/RRDtools.pm169
5 files changed, 196 insertions, 3 deletions
diff --git a/CHANGES b/CHANGES
index 2903d33..68ef682 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,4 @@
+* check at startup that existing RRD files conform to the config specifications -- niko
* 3 pings is the official minimum now -- niko
* graph fixes for small numbers of pings -- Chris Wilson <chris *aidworld.org>
* fix the LDAP probe killing the CGI with perl <5.6 -- Peter Farmer <pfarmer *hashbang.org.uk>
diff --git a/Makefile b/Makefile
index d0048f4..bb56142 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ GROFF = groff
DOCS = $(filter-out doc/smokeping_config.pod doc/smokeping.pod doc/smokeping.cgi.pod,$(wildcard doc/*.pod)) doc/smokeping_examples.pod # section 7
DOCSCONFIG := doc/smokeping_config.pod # section 5
-PM := lib/ISG/ParseConfig.pm lib/Smokeping.pm lib/Smokeping/Examples.pm
+PM := lib/ISG/ParseConfig.pm lib/Smokeping.pm lib/Smokeping/Examples.pm lib/Smokeping/RRDtools.pm
PODPROBE := $(wildcard lib/Smokeping/probes/*.pm)
PODMATCH := $(wildcard lib/Smokeping/matchers/*.pm)
@@ -42,6 +42,8 @@ doc/Smokeping.3: lib/Smokeping.pm
$(POD2MAN) --section 3 > $@
doc/Smokeping/Examples.3: lib/Smokeping/Examples.pm
$(POD2MAN) --section 3 > $@
+doc/Smokeping/RRDtools.3: lib/Smokeping/RRDtools.pm
+ $(POD2MAN) --section 3 > $@
doc/Smokeping/probes/%.pod: lib/Smokeping/probes/%.pm
$(MAKEPOD) Smokeping::probes::$* > $@
@@ -63,6 +65,9 @@ doc/Smokeping.html: lib/Smokeping.pm
$(POD2HTML)
doc/Smokeping/Examples.html: lib/Smokeping/Examples.pm
$(POD2HTML)
+doc/Smokeping/RRDtools.html: lib/Smokeping/RRDtools.pm
+ $(POD2HTML)
+
doc/Smokeping/matchers/%.html: lib/Smokeping/matchers/%.pm
$(POD2HTML)
doc/ISG/%.html: lib/ISG/%.pm
@@ -95,6 +100,7 @@ rename-man: $(MAN)
done
mv doc/ISG/ParseConfig.3 doc/ISG/ISG::ParseConfig.3
mv doc/Smokeping/Examples.3 doc/Smokeping/Smokeping::Examples.3
+ mv doc/Smokeping/RRDtools.3 doc/Smokeping/Smokeping::RRDtools.3
ref: doc/smokeping_config.pod
diff --git a/doc/smokeping_upgrade.pod b/doc/smokeping_upgrade.pod
index ac393aa..36587d9 100644
--- a/doc/smokeping_upgrade.pod
+++ b/doc/smokeping_upgrade.pod
@@ -101,6 +101,17 @@ The C<pings> variable now has an enforced minimum value of 3, as the
whole design of Smokeping is based on the idea of sending several probes
and measuring and visualizing the variation between them.
+=item RRD parameter checking
+
+Smokeping now checks at startup that the parameters of any existing RRD files
+match those specified in the configuration file. If there is a discrepancy,
+it will give an error message and refuse to start.
+
+This situation is most likely to happen if you have modified the C<step>
+or C<pings> variables in your configuration file. You'll then have to
+delete the old RRD file or somehow convert it to use the new parameters.
+The C<rrdtune> command might be helpful here.
+
=back
In addition to this, some probes have had minor incompatible changes to
diff --git a/lib/Smokeping.pm b/lib/Smokeping.pm
index 65ac92b..82113a3 100644
--- a/lib/Smokeping.pm
+++ b/lib/Smokeping.pm
@@ -16,6 +16,7 @@ setlogsock('unix')
if grep /^ $^O $/xo, ("linux", "openbsd", "freebsd", "netbsd");
use File::Basename;
use Smokeping::Examples;
+use Smokeping::RRDtools;
# globale persistent variables for speedy
use vars qw($cfg $probes $VERSION $havegetaddrinfo $cgimode);
@@ -359,8 +360,7 @@ sub init_target_tree ($$$$) {
}
my $pings = $probeobj->_pings($tree);
- if (not -f $name.".rrd"){
- my @create =
+ my @create =
($name.".rrd", "--step",$step,
"DS:uptime:GAUGE:".(2*$step).":0:U",
"DS:loss:GAUGE:".(2*$step).":0:".$pings,
@@ -369,10 +369,16 @@ sub init_target_tree ($$$$) {
(map { "DS:ping${_}:GAUGE:".(2*$step).":0:180" }
1..$pings),
(map { "RRA:".(join ":", @{$_}) } @{$cfg->{Database}{_table}} ));
+ if (not -f $name.".rrd"){
do_debuglog("Calling RRDs::create(@create)");
RRDs::create(@create);
my $ERROR = RRDs::error();
do_log "RRDs::create ERROR: $ERROR\n" if $ERROR;
+ } else {
+ shift @create; # remove the filename
+ 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;
}
}
}
diff --git a/lib/Smokeping/RRDtools.pm b/lib/Smokeping/RRDtools.pm
new file mode 100644
index 0000000..7260cca
--- /dev/null
+++ b/lib/Smokeping/RRDtools.pm
@@ -0,0 +1,169 @@
+package Smokeping::RRDtools;
+
+=head1 NAME
+
+Smokeping::RRDtools - Tools for RRD file handling
+
+=head1 SYNOPSYS
+
+ use Smokeping::RRDtools;
+ use RRDs;
+
+ my $file = '/path/to/file.rrd';
+
+ # get the create arguments that $file was created with
+ my $create = Smokeping::RRDtools::info2create($file);
+
+ # use them to create a new file
+ RRDs::create('/path/to/file2.rrd', @$create);
+
+ # or compare them against another create list
+ my @create = ('--step', 60, 'DS:ds0:GAUGE:120:0:U', 'RRA:AVERAGE:0.5:1:1008');
+ my $comparison = Smokeping::RRDtools::compare($file, \@create);
+ print "Create arguments didn't match: $comparison\n" if $comparison;
+
+=head1 DESCRIPTION
+
+This module offers two functions, C<info2create> and C<compare>.
+The first can be used to recreate the arguments that an RRD file
+was created with. The second checks if an RRD file was created
+with the given arguments.
+
+The function C<info2create> must be called with one argument:
+the path to the interesting RRD file. It will return an array
+reference of the argument list that can be fed to C<RRDs::create>.
+Note that this list will never contain the C<start> parameter,
+but it B<will> contain the C<step> parameter.
+
+The function C<compare> must be called with two arguments: the path
+to the interesting RRD file, and a reference to an argument list that
+could be fed to C<RRDs::create>. The function will then simply compare
+the result of C<info2create> with this argument list. It will return
+C<undef> if the arguments matched, and a string indicating the difference
+if a discrepancy was found. Note that if there is a C<start> parameter in
+the argument list, C<compare> disregards it. If C<step> isn't specified,
+C<compare> will use the C<rrdtool> default of 300 seconds.
+
+=head1 NOTES
+
+This module is not particularly specific to Smokeping, it is just
+distributed with it.
+
+=head1 BUGS
+
+Probably.
+
+=head1 COPYRIGHT
+
+Copyright (c) 2005 by Niko Tyni.
+
+=head1 LICENSE
+
+This program is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more
+details.
+
+You should have received a copy of the GNU General Public
+License along with this program; if not, write to the Free
+Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+02139, USA.
+
+=head1 SEE ALSO
+
+RRDs(3)
+
+=cut
+
+use strict;
+use RRDs;
+
+# take an RRD file and make a create list out of it
+sub info2create {
+ my $file = shift;
+ my @create;
+ my $info = RRDs::info($file);
+ my $error = RRDs::error;
+ die("RRDs::info $file: ERROR: $error") if $error;
+ die("$file: unknown RRD version: $info->{rrd_version}")
+ unless $info->{rrd_version} eq '0001';
+ my $cf = $info->{"rra[0].cf"};
+ die("$file: no RRAs found?")
+ unless defined $cf;
+ my @fetch = RRDs::fetch($file, $cf);
+ $error = RRDs::error;
+ die("RRDs::fetch $file $cf: ERROR: $error") if $error;
+ my @ds = @{$fetch[2]};
+
+ push @create, '--step', $info->{step};
+ for my $ds (@ds) {
+ my @s = ("DS", $ds);
+ for (qw(type minimal_heartbeat min max)) {
+ die("$file: missing $_ for DS $ds?")
+ unless exists $info->{"ds[$ds].$_"};
+ my $val = $info->{"ds[$ds].$_"};
+ push @s, defined $val ? $val : "U";
+ }
+ push @create, join(":", @s);
+ }
+ for (my $i=0; exists $info->{"rra[$i].cf"}; $i++) {
+ my @s = ("RRA", $info->{"rra[$i].cf"});
+ for (qw(xff pdp_per_row rows)) {
+ die("$file: missing $_ for RRA $i")
+ unless exists $info->{"rra[$i].$_"};
+ push @s, $info->{"rra[$i].$_"};
+ }
+ push @create, join(":", @s);
+ }
+ return \@create;
+}
+
+sub compare {
+ my $file = shift;
+ my $create = shift;
+ my @create2 = @{info2create($file)};
+ my @create = @$create; # copy because we change it
+ # we don't compare the '--start' param
+ if ($create[0] eq '--start') {
+ shift @create;
+ shift @create;
+ }
+ # special check for the optional 'step' parameter
+ die("Internal error: didn't get the step parameter from info2create?")
+ unless ("--step" eq shift @create2);
+ my $step = shift @create2;
+ my $step2;
+ if ($create[0] eq '--step') {
+ shift @create;
+ $step2 = shift @create;
+ } else {
+ $step2 = 300; # default value
+ }
+ return "Wrong value of step: $file has $step, create string has $step2"
+ unless $step == $step2;
+
+ my $dscount = grep /^DS/, @create;
+ my $dscount2 = grep /^DS/, @create2;
+ return "Different number of data sources: $file has $dscount2, create string has $dscount"
+ unless $dscount == $dscount2;
+ my $rracount = grep /^RRA/, @create;
+ my $rracount2 = grep /^RRA/, @create2;
+ return "Different number of RRAs: $file has $rracount2, create string has $rracount"
+ unless $rracount == $rracount2;
+
+ while (my $arg = shift @create) {
+ my $arg2 = shift @create2;
+ return "Different arguments: $file has $arg2, create string has $arg"
+ unless $arg eq $arg2;
+ }
+ return undef;
+}
+
+1;