summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile32
-rwxr-xr-xbin/smokeping.dist12
-rw-r--r--doc/smokeping_extend.pod241
-rw-r--r--doc/smokeping_upgrade.pod199
-rw-r--r--etc/config-echoping.dist82
-rw-r--r--lib/ISG/ParseConfig.pm20
-rw-r--r--lib/Smokeping.pm543
-rw-r--r--lib/Smokeping/Examples.pm633
-rw-r--r--lib/probes/AnotherDNS.pm153
-rw-r--r--lib/probes/AnotherSSH.pm202
-rw-r--r--lib/probes/CiscoRTTMonDNS.pm131
-rw-r--r--lib/probes/CiscoRTTMonEchoICMP.pm163
-rw-r--r--lib/probes/CiscoRTTMonTcpConnect.pm154
-rw-r--r--lib/probes/Curl.pm186
-rw-r--r--lib/probes/DNS.pm119
-rw-r--r--lib/probes/EchoPing.pm227
-rw-r--r--lib/probes/EchoPingChargen.pm61
-rw-r--r--lib/probes/EchoPingDiscard.pm46
-rw-r--r--lib/probes/EchoPingHttp.pm143
-rw-r--r--lib/probes/EchoPingHttps.pm59
-rw-r--r--lib/probes/EchoPingIcp.pm92
-rw-r--r--lib/probes/EchoPingSmtp.pm63
-rw-r--r--lib/probes/FPing.pm139
-rw-r--r--lib/probes/FPing.pm.orig115
-rw-r--r--lib/probes/FPing6.pm105
-rw-r--r--lib/probes/IOSPing.pm184
-rw-r--r--lib/probes/LDAP.pm179
-rw-r--r--lib/probes/Radius.pm212
-rw-r--r--lib/probes/RemoteFPing.pm208
-rw-r--r--lib/probes/SSH.pm95
-rw-r--r--lib/probes/base.pm199
-rw-r--r--lib/probes/basefork.pm178
-rw-r--r--lib/probes/basevars.pm95
-rw-r--r--lib/probes/passwordchecker.pm74
-rw-r--r--lib/probes/skel.pm134
-rw-r--r--lib/probes/telnetIOSPing.pm180
36 files changed, 3668 insertions, 1990 deletions
diff --git a/Makefile b/Makefile
index fd96fd6..a795c3e 100644
--- a/Makefile
+++ b/Makefile
@@ -2,32 +2,40 @@ SHELL = /bin/sh
VERSION = 1.38
IGNORE = ~|CVS|var/|smokeping-$(VERSION)/smokeping-$(VERSION)|cvsignore|rej|orig|DEAD
GROFF = groff
-.PHONY: man html txt ref patch killdoc doc tar
+.PHONY: man html txt ref examples check-examples patch killdoc doc tar
.SUFFIXES:
.SUFFIXES: .pm .pod .txt .html .man .1
-POD := doc/$(wildcard doc/*.pod) lib/ISG/ParseConfig.pm \
+POD := $(wildcard doc/*.pod) lib/ISG/ParseConfig.pm \
lib/Smokeping.pm
-PODPROBE := lib/probes/$(wildcard lib/probes/*.pm)
-PODMATCH := lib/matchers/$(wildcard lib/matchers/*.pm)
+PODPROBE := $(wildcard lib/probes/*.pm)
+PODMATCH := $(wildcard lib/matchers/*.pm)
-BASE = $(addprefix doc/,$(subst .pod,,$(notdir $(POD)))) $(addprefix doc/probes/,$(subst .pod,,$(notdir $(PODPROBE)))) $(addprefix doc/matchers/,$(subst .pod,,$(notdir $(PODMATCH))))
+BASE = $(addprefix doc/,$(subst .pod,,$(notdir $(POD)))) $(subst .pm,,$(subst lib/probes,doc/probes,$(PODPROBE))) $(addprefix doc/matchers/,$(subst .pod,,$(notdir $(PODMATCH)))) doc/smokeping
MAN = $(addsuffix .1,$(BASE))
TXT = $(addsuffix .txt,$(BASE))
HTML= $(addsuffix .html,$(BASE))
POD2MAN = pod2man --release=$(VERSION) --center=SmokePing $< > $@
POD2HTML= cd doc ; pod2html --infile=../$< --outfile=../$@ --noindex --htmlroot=. --podroot=. --podpath=. --title=$*
+# we go to this trouble to ensure that MAKEPOD only uses modules in the installation directory
+MAKEPOD= perl -Ilib -I/usr/pack/rrdtool-1.0.47-to/lib/perl -mSmokeping -e 'Smokeping::main()' -- --makepod
+GENEX= perl -Ilib -I/usr/pack/rrdtool-1.0.47-to/lib/perl -mSmokeping -e 'Smokeping::main()' -- --gen-examples
+
doc/%.1: doc/%.pod
$(POD2MAN)
doc/%.1: lib/%
$(POD2MAN)
-doc/probes/%.1: lib/probes/%
+doc/probes/%.pod: lib/probes/%.pm
+ $(MAKEPOD) probes::$* > $@
+doc/probes/%.1: doc/probes/%.pod
$(POD2MAN)
doc/matchers/%.1: lib/matchers/%
$(POD2MAN)
doc/%.1: lib/ISG/%
$(POD2MAN)
+doc/smokeping.1: bin/smokeping.dist
+ $(POD2MAN)
doc/%.html: doc/%.pod
$(POD2HTML)
@@ -35,7 +43,7 @@ doc/%.html: lib/%
$(POD2HTML)
doc/%.html: lib/ISG/%
$(POD2HTML)
-doc/probes/%.html: lib/probes/%
+doc/probes/%.html: doc/probes/%.pod
$(POD2HTML)
doc/matchers/%.html: lib/matchers/%
$(POD2HTML)
@@ -55,8 +63,16 @@ txt: $(TXT)
ref: doc/smokeping_config.pod
+examples:
+ $(GENEX)
+
+check-examples:
+ $(GENEX) --check
+
doc/smokeping_config.pod: lib/Smokeping.pm
- perl -Ilib -I/usr/pack/rrdtool-1.0.47-to/lib/perl -mSmokeping ./bin/smokeping.dist --makepod > doc/smokeping_config.pod
+ $(MAKEPOD) > $@
+doc/smokeping_examples.pod: lib/Smokeping/Examples.pm etc/config.dist
+ $(GENEX)
patch:
perl -i~ -p -e 's/VERSION="\d.*?"/VERSION="$(VERSION)"/' lib/Smokeping.pm
perl -i~ -p -e 's/Smokeping \d.*?;/Smokeping $(VERSION);/' bin/smokeping.dist htdocs/smokeping.cgi.dist
diff --git a/bin/smokeping.dist b/bin/smokeping.dist
index 701e3a6..0d193d5 100755
--- a/bin/smokeping.dist
+++ b/bin/smokeping.dist
@@ -18,13 +18,17 @@ B<smokeping> [ B<--email> | B<--makepod> | B<--version> | B<--restart> ]
Options:
- --man Show the manpage
+ --man[=x] Show the manpage for the program (or for probe x, if specified)
--help Help :-)
--email Send SmokePing Agents to all Targets marked DYNAMIC
- --makepod Create POD documentation on Config file
+ --config=x Use a config file different from the default
+
+ --check Just check the config file syntax, don't start the daemon
+
+ --makepod[=x] Create POD documentation on Config file (or for probe x, if specified)
--version Show SmokePing Version
@@ -45,6 +49,10 @@ B<smokeping> [ B<--email> | B<--makepod> | B<--version> | B<--restart> ]
--nosleep For debugging you may want to run SmokePing without sleep interval
+ --gen-examples Generate the smokeping_examples document and example config files
+ (to be used while building inside the smokeping distribution)
+ With --check : check the syntax of the generated examples.
+
=head1 DESCRIPTION
The B<smokeping> tool is the commandline part of the SmokePing system. Its
diff --git a/doc/smokeping_extend.pod b/doc/smokeping_extend.pod
new file mode 100644
index 0000000..6ee0133
--- /dev/null
+++ b/doc/smokeping_extend.pod
@@ -0,0 +1,241 @@
+=head1 NAME
+
+smokeping_extend - Notes on extending Smokeping
+
+=head1 OVERVIEW
+
+This document is intended to guide prospective authors in writing new
+Smokeping probes. It mostly describes the interface between Smokeping
+and its probe modules. If it seems too complicated to understand, look
+at the existing modules for examples.
+
+Comments and proposed changes or additions are welcome. Please send
+them to the smokeping-users mailing list. Patches against this file
+are most appreciated.
+
+=head1 CHOOSING A BASE CLASS
+
+The first thing you should decide is which base class you should
+use for your probe. For most (if not all) uses it's a choice between
+C<probes::base> and C<probes::basefork>. The former is intended for probes
+that can measure their targets all in one go, while the latter is for
+probing them one at a time, possibly in several concurrent subprocesses.
+
+At the moment, the only probes that use C<probes::base> are the FPing
+derivatives. All the others use C<probes::basefork>, and chances are
+you should too. This document will thus concentrate on the latter case.
+
+=head1 SKELETON FILE
+
+The C<probes::skel> module is a non-functional probe that is intended
+to make a good basis for a new probe module. Copy the file,
+C<lib/probes/skel.pm>, to a new name and just fill out the blanks :)
+Note that real probe modules must have at least one capital letter
+in their name.
+
+=head1 PROBE DOCUMENTATION
+
+The probe documentation is generated from the source code with the
+C<smokeping> arguments C<--man> or C<--makepod>. The embedded
+POD documentation should point to this real documentation, so
+that curious users of the C<perldoc> command see what's going on.
+All the current probes do this.
+
+You should provide the method C<pod_hash> that returns a reference to
+a hash with keys corresponding to the section names you want in the
+manpage. The supported section names are
+C<name>, C<overview>, C<description>, C<authors>, C<notes>, C<bugs>, and
+C<see_also>. If you don't need a particular section, just leave it out.
+
+The special sections C<synopsys> and C<variables> are automatically
+generated from the description of your variables. See below.
+
+=head1 PROBE DESCRIPTION
+
+The probe should offer the C<ProbeDesc> method that returns a short
+description of what it does. This will be used in the graphs produced
+by the web frontend.
+
+=head1 VARIABLES
+
+All Smokeping probes must define their variables by implementing a
+C<probevars> method for probe-specific variables and a C<targetvars>
+method for target-specific variables. If you don't know the difference
+between these yet, see the L<smokeping_examples> document.
+
+(The probes that are derived from C<probes::base> don't support
+target-specific variables, so they only use the C<probevars> method.)
+
+The base classes offer these methods too to provide the variables that
+are common to all the probes (eg. the probe-specific C<step> variable
+and the target-specific C<pings> variable. If you don't want to add
+anything to the base class variables (perhaps because all your variables
+are of a target-specific nature, so you don't need new probe-specific
+variables at all), you can leave the corresponding method out and it
+will be inherited from the base class.
+
+When you do supply your own C<probevars> or C<targetvars> method, you should
+combine your variables with those coming from the superclass. There is a
+convenience method called C<_makevars> that does this, and the common idiom is
+
+ sub probevars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::probevars, {
+ # your variables go here
+ }
+ }
+
+The variables are declared in a syntax that comes from the module used
+for parsing the configuration file, C<ISG::ParseConfig>. Each variable
+should be a hash that uses the "special variable keys" documented in
+the C<ISG::ParseConfig> manual. See the C<probes::skel> and the other
+probes for examples.
+
+For reference, here are the keys the hash should have. Much of this
+is taken straight from the C<ISG::ParseConfig> manual.
+
+=over
+
+=item Keys you B<must> provide
+
+=over
+
+=item _doc
+
+Description of the variable.
+
+=item _example
+
+An example value. This will be used in the SYNOPSYS section in the
+probe manual.
+
+=back
+
+=item Optional keys
+
+=over
+
+=item _default
+
+A default value that will be assigned to the variable if none is specified or inherited.
+
+=item _re
+
+Regular expression upon which the value will be checked.
+
+=item _re_error
+
+String containing the returned error in case the regular expression
+doesn't match (if not specified, a generic 'syntax error' message will
+be returned).
+
+=item _sub
+
+A function pointer. It called for every value, with the value passed
+as its first argument. If the function returns a defined value it is
+assumed that the test was not successful and an error is generated with
+the returned string as content.
+
+=back
+
+=back
+
+The C<probevars> and C<targetvars> methods should return hash references
+that contain the variable names as keys and the hashes described above
+as values. In addition the C<ISG::ParseConfig> special section key
+C<_mandatory> is supported and should contain a reference to a list of
+mandatory variables. The C<_makevars> method is available of this special
+key and merges the mandatory lists in its arguments. Note that no other
+C<ISG::ParseConfig> special section keys are supported.
+
+=head1 INITIALIZATION
+
+If you must do something at probe initialization time, like check that
+the external program you're going to use behaves as you expect, you should
+do it in the C<new> method. You should probably also take care that
+you don't run the tests needlessly while in CGI mode. The usual way to
+do this is to test for $ENV{SERVER_SOFTWARE}. See the C<probes::skel>
+module for an example.
+
+=head1 PINGING
+
+All the real action happens in the C<pingone> method (or, for
+C<probes::base>-derived probes, in the C<ping> method.) The arguments
+for C<pingone> are C<$self>, the module instance (since this is a method)
+and C<$target>, the target to be probed.
+
+You can access the probe-specific variables here via the
+C<$self-E<gt>{properties}> hash and the target-specific ones via the
+C<$target-E<gt>{vars}> hash. You get the number of pings needed for
+the target via the C<pings> method: C<my $count = $self-E<gt>pings($target)>.
+
+You should return a sorted array of the latency times measured. If a ping
+fails, don't put anything in the array.
+
+That's it, you're done!
+
+=head1 TIMEOUT HANDLING
+
+If you deal with timeouts (for example because your program offers a parameter
+for specifying the timeout for the pings), you should know a few things.
+
+First, there's timeout logic in C<probes::basefork> that kills the probe
+when the timeout is reached. By default the timeout is (# of pings *
+5 seconds) + 1 second. If you expect that your pings can take longer,
+you should modify the default value of the probe-specific variable C<timeout>.
+This would be done like this:
+
+ sub probevars {
+ my $class = shift;
+ my $h = $class->SUPER::probevars;
+ $h->{timeout}{_default} = 10; # override the superclass default
+ return $class->_makevars($h, {
+ # your variables go here
+ }
+ }
+
+If you want to provide a target-specific C<timeout> setting, you should
+delete the probe-specific variable and be sure to provide a default for
+your target-specific one. See eg. C<probes::AnotherDNS> for an example of
+how this is done.
+
+Providing a target-specific C<timeout> will make the timeout in
+C<probes::basefork> be (# of pings * the maximum timeout of all targets)
++ 1 second. The 1 second is added so that the own timeout logic of the
+probe has time to kick in even in the worst case (ie. all pings are lost)
+before C<probes::basefork> starts killing the processes.
+
+=head1 COPYRIGHT
+
+Copyright 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 AUTHOR
+
+Niko Tyni <ntyni@iki.fi>
+
+=head1 BUGS
+
+This document makes writing new probes look much harder than it really is.
+
+=head1 SEE ALSO
+
+The other Smokeping documents, especially smokeping_config.
diff --git a/doc/smokeping_upgrade.pod b/doc/smokeping_upgrade.pod
new file mode 100644
index 0000000..edb1d6c
--- /dev/null
+++ b/doc/smokeping_upgrade.pod
@@ -0,0 +1,199 @@
+=head1 NAME
+
+smokeping_upgrade - Notes on upgrading Smokeping
+
+=head1 OVERVIEW
+
+This document tries to list incompatible or otherwise user-visible changes
+in Smokeping versions, with instructions on how to fix any possible
+problems. It also sporadically mentions new features and the like.
+
+The document currently starts with changes from 1.34 to 1.37. If you
+run into problems with upgrading from earlier versions, please send
+a description of the problems, preferably with notes on how to fix
+them, to the C<smokeping-users> mailing list, so they can be added to
+this document. The same applies to any problems you find with current
+versions that are not documented here, of course. Patch submissions
+against this file are most appreciated.
+
+If a version is not listed, there are no known problems in upgrading
+to it from the previous release.
+
+An official list of changes with each release can be found in the CHANGES
+file in the Smokeping distribution. This document tries to complement
+that with upgrading instructions etc.
+
+=head1 1.38 to 2.0
+
+The biggest change with the 2.0 release is that the configuration file
+is now parsed much more strictly. This should result in (hopefully
+understandable) error messages making the configuration less of the
+trial-and-error variety than it used to be. It also automates the
+generation of the configuration documentation from the source code,
+so the docs are now more accurate.
+
+The configuration syntax has stayed mostly the same, except for the
+issues below.
+
+=over
+
+=item PROBE_CONF
+
+The PROBE_CONF subsections have been deprecated. All the target-specific
+variables are now configured in the same section as the target is. Just
+deleting the
+
+++ PROBE_CONF
+
+lines should fix this (for any number of '+', obviously.)
+
+The existence of a PROBE_CONF section makes smokeping exit with an error
+message at parse time.
+
+Note for distributors: these lines could easily be removed automatically
+during upgrade.
+
+=item Variable order
+
+The C<probe> variable must now be set before any variables that depend on
+the selected probe. This is because setting C<probe> modifies the grammar
+of the rest of the section dynamically at parse time.
+
+Additionally, C<probe> must now precede C<host>, for reasons that have
+to do with the current implementation of mandatory variable checking.
+
+Both of these errors are recognized at parse time and produce error messages
+accordingly.
+
+Note for distributors: the C<smokeping> command now has a new '--check'
+option that can be used to verify the syntax of the configuration
+file. It might be a good idea to do this on upgrade and give the user
+an explanatory note if the verification fails.
+
+=item Target-specific variables in the Probes section
+
+This is not an incompatible change, but it is mentioned here nevertheless.
+Target-specific variables can now be specified in the Probes section as well,
+and the values given become defaults for all the targets.
+
+=back
+
+In addition to this, some probes have had minor incompatible changes to
+their configuration.
+
+=over
+
+=item RemoteFPing
+
+The C<rbinary> variable is now mandatory. This is a side effect from a bigger change:
+the probe is now derived from the FPing probe and supports all the variables
+FPing does.
+
+=item FPing6
+
+This probe is also now derived from FPing and supports all the variables FPing does.
+
+=item Curl
+
+The URL that will be used is now specified with the variable C<urlformat> instead
+of C<url>. The new variable can (and usually should) include a placeholder
+for the C<host> variable of each target as C<%host%>, eg. C<urlformat = http://%host%/>.
+The new variable is mandatory.
+
+The change was made to fix the confusing situation where the C<host> variable
+was required for each actual target, but it didn't actually have any effect
+(as the server to be probed came from the C<url> variable.)
+
+=item EchoPingIcp
+
+The C<url> variable is now mandatory, as the old default "/" didn't make
+sense because it's relative rather than absolute.
+
+=item LDAP
+
+The C<filter> variable is now mandatory, as Net::LDAP bails out without it.
+
+The C<sleeptime> variable was changed to C<mininterval> and its semantics
+were changed accordingly (it's now the minimum time between two queries
+rather than the time slept between the end of one and the start of the
+another.)
+
+=item Radius
+
+The C<sleeptime> variable was changed to C<mininterval> and its semantics
+were changed accordingly. See the LDAP explanation above.
+
+=item AnotherDNS
+
+The C<sleeptime> variable was changed to C<mininterval> and its semantics
+were changed accordingly. See the LDAP explanation above. Additionally,
+the time is now specified in seconds rather than microseconds.
+
+=item AnotherSSH
+
+The C<sleeptime> variable was changed to C<mininterval> and its semantics
+were changed accordingly. See the LDAP explanation above. Additionally,
+the time is now specified in seconds rather than microseconds.
+
+=item telnetIOSPing
+
+The C<target> variable was removed. The target should now be specified
+in the C<host> variable, like it is with all the other probes.
+
+=back
+
+=head1 1.34 to 1.37
+
+=over
+
+=item The RemoteFPing probe
+
+The configuration of this probe was moved from the Targets section to the
+Probes section, as all the variables are really probe-specific. The moved
+variables were C<rhost>, C<rbinary> and C<rhost>.
+
+=item Logging changes
+
+The C<smokeping> daemon now warns at startup if syslog support is not turned on
+in the config file. This is because many diagnostic messages will otherwise
+get lost.
+
+=item Concurrent probes
+
+Each probe now runs in its own process, instead of them all running
+sequentially in one process. This makes it possible to specify different
+step lengths for different probes. You can get the old behaviour back
+by setting 'concurrentprobes = no'.
+
+=back
+
+=head1 COPYRIGHT
+
+Copyright 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 AUTHOR
+
+Niko Tyni <ntyni@iki.fi>
+
+=head1 SEE ALSO
+
+The other Smokeping documents, especially smokeping_config.
diff --git a/etc/config-echoping.dist b/etc/config-echoping.dist
deleted file mode 100644
index 2aa7678..0000000
--- a/etc/config-echoping.dist
+++ /dev/null
@@ -1,82 +0,0 @@
-# only the relevant sections are included, see smokeping distribution
-# for the rest of them
-
-*** Probes ***
-
-# these expect to find echoping in /usr/bin
-# if not, you'll have to specify the location separately for each probe
-# + EchoPing # uses TCP or UDP echo (port 7)
-# + EchoPingDiscard # uses TCP or UDP discard (port 9)
-# + EchoPingChargen # uses TCP chargen (port 19)
-+ EchoPingSmtp # SMTP (25/tcp) for mail servers
-+ EchoPingHttps # HTTPS (443/tcp) for web servers
-+ EchoPingHttp # HTTP (80/tcp) for web servers and caches
-+ EchoPingIcp # ICP (3130/udp) for caches
-
-*** Targets ***
-
-# default probe
-probe = FPing
-
-menu = Top
-title = Network Latency Grapher
-remark = Welcome to the SmokePing website of xxx Company. \
- Here you will learn all abou the latency of our network.
-
-+ MyServers
-
-menu = My Servers
-title = My Servers
-
-++ www-server
-menu = www-server
-title = Web Server (www-server) / ICMP
-# probe = FPing propagated from top
-host = www-server.abc
-
-+++ http
-menu = http
-title = Web Server (www-server) / HTTP
-probe = EchoPingHttp
-host = www-server.abc
-# default url is /
-
-+++ https
-menu = https
-title = Web Server (www-server) / HTTPS
-probe = EchoPingHttps
-host = www-server.abc
-
-++ cache
-menu = www-cache
-title = Web Cache (www-cache) / ICMP
-host = www-cache.abc
-
-+++ http
-menu = http
-title = www-cache / HTTP
-host = www-cache.abc
-probe = EchoPingHttp
-++++ PROBE_CONF
-port = 8080 # use the squid port
-url = http://www.microsoft.com/
-
-+++ icp
-menu = icp
-title = www-cache / ICP
-host = www-cache.abc
-probe = EchoPingIcp
-++++ PROBE_CONF
-url = http://www.microsoft.com/
-
-++ mail
-menu = mail-server
-title = Mail Server (mail-server) / ICMP
-host = mail-server.abc
-
-+++ smtp
-menu = mail-server / SMTP
-title = Mail Server (mail-server) / SMTP
-host = mail-server.abc
-probe = EchoPingSmtp
-
diff --git a/lib/ISG/ParseConfig.pm b/lib/ISG/ParseConfig.pm
index ff72e59..7903972 100644
--- a/lib/ISG/ParseConfig.pm
+++ b/lib/ISG/ParseConfig.pm
@@ -75,6 +75,7 @@ sub _deepcopy {
/^HASH$/ and return { map { $_ => $what->{$_} eq $what ?
$what->{$_} : _deepcopy($what->{$_}) } keys %$what };
/^CODE$/ and return $what; # we don't need to copy the subs
+ /^Regexp$/ and return $what; # neither Regexp objects
}
die "Cannot _deepcopy reference type @{[ref $what]}";
}
@@ -674,6 +675,14 @@ sub _genpod($$$){
" I<(mandatory setting)>" : "";
push @{$doc}, "=item B<$var>".$mandatory;
push @{$doc}, $tree->{$var}{_doc} if $tree->{$var}{_doc} ;
+ my $inherited = $tree->{_inherited} and
+ grep {$_ eq $var} @{$tree->{_inherited}};
+ push @{$doc}, "This variable I<inherits> its value from the parent section if nothing is specified here."
+ if $inherited;
+ push @{$doc}, "This variable I<dynamically> modifies the grammar based on its value."
+ if $tree->{$var}{_dyn};
+ push @{$doc}, "Default value: $var = $tree->{$var}{_default}"
+ if ($tree->{$var}{_default});
push @{$doc}, "Example: $var = $tree->{$var}{_example}"
if ($tree->{$var}{_example})
}
@@ -718,8 +727,15 @@ sub _genpod($$$){
"=head2 *** $section ***$mandatory";
push @{$doc}, ($tree->{$section}{_doc})
if $tree->{$section}{_doc};
- _genpod ($tree->{$section},$level+1,$doc)
- unless $tree eq $tree->{$section};
+ push @{$doc}, "The grammar of this section is I<dynamically> modified based on its name."
+ if $tree->{$section}{_dyn};
+ if ($tree eq $tree->{$section} or
+ ($tree->{_recursive} and
+ grep {$_ eq $section} @{$tree->{_recursive}})) {
+ push @{$doc}, "This section is I<recursive>: it can contain subsection(s) with the same syntax.";
+ } else {
+ _genpod ($tree->{$section},$level+1,$doc)
+ }
}
diff --git a/lib/Smokeping.pm b/lib/Smokeping.pm
index 9f66792..b1d258d 100644
--- a/lib/Smokeping.pm
+++ b/lib/Smokeping.pm
@@ -15,6 +15,7 @@ use Sys::Syslog qw(:DEFAULT setlogsock);
setlogsock('unix')
if grep /^ $^O $/xo, ("linux", "openbsd", "freebsd", "netbsd");
use File::Basename;
+use Smokeping::Examples;
# globale persistent variables for speedy
use vars qw($cfg $probes $VERSION $havegetaddrinfo $cgimode);
@@ -33,6 +34,18 @@ my $DEFAULTPRIORITY = 'info'; # default syslog priority
my $logging = 0; # keeps track of whether we have a logging method enabled
+sub find_probedir {
+ # find the directory where the probe modules are located
+ # by looking for 'probes/FPing.pm' in @INC
+ #
+ # yes, this is ugly. Suggestions welcome.
+ for (@INC) {
+ -f "$_/probes/FPing.pm" or next;
+ return "$_/probes";
+ }
+ return undef;
+}
+
sub do_log(@);
sub load_probe($$$$);
@@ -43,13 +56,7 @@ sub load_probes ($){
my @subprobes = grep { ref $cfg->{Probes}{$probe}{$_} eq 'HASH' } keys %{$cfg->{Probes}{$probe}};
if (@subprobes) {
my $modname = $probe;
- my %properties = %{$cfg->{Probes}{$probe}};
- delete @properties{@subprobes};
for my $subprobe (@subprobes) {
- for (keys %properties) {
- $cfg->{Probes}{$probe}{$subprobe}{$_} = $properties{$_}
- unless exists $cfg->{Probes}{$probe}{$subprobe}{$_};
- }
$prbs{$subprobe} = load_probe($modname, $cfg->{Probes}{$probe}{$subprobe},$cfg, $subprobe);
}
} else {
@@ -65,8 +72,6 @@ sub load_probe ($$$$) {
my $cfg = shift;
my $name = shift;
$name = $modname unless defined $name;
- eval 'require probes::'.$modname;
- die "$@\n" if $@;
my $rv;
eval '$rv = probes::'.$modname.'->new( $properties,$cfg,$name);';
die "$@\n" if $@;
@@ -305,32 +310,12 @@ sub check_filter ($$) {
return 1;
}
-sub init_target_tree ($$$$$$$$); # predeclare recursive subs
-sub init_target_tree ($$$$$$$$) {
+sub init_target_tree ($$$$); # predeclare recursive subs
+sub init_target_tree ($$$$) {
my $cfg = shift;
my $probes = shift;
- my $probe = shift;
my $tree = shift;
my $name = shift;
- my $PROBE_CONF = shift;
- my $alerts = shift;
- my $alertee = shift;
-
- # inherit probe type from parent
- if (not defined $tree->{probe} or $tree->{probe} eq $probe){
- $tree->{probe} = $probe;
- # inherit parent values if the probe type has not changed
- for (keys %$PROBE_CONF) {
- $tree->{PROBE_CONF}{$_} = $PROBE_CONF->{$_}
- unless exists $tree->{PROBE_CONF}{$_};
- }
- };
-
- $tree->{alerts} = $alerts
- if not defined $tree->{alerts} and defined $alerts;
-
- $tree->{alertee} = $alertee
- if not defined $tree->{alertee} and defined $alertee;
if ($tree->{alerts}){
die "ERROR: no Alerts section\n"
@@ -349,12 +334,11 @@ sub init_target_tree ($$$$$$$$) {
$tree->{title} ||= $tree->{host} || "unknown";
foreach my $prop (keys %{$tree}) {
- next if $prop eq 'PROBE_CONF';
if (ref $tree->{$prop} eq 'HASH'){
if (not -d $name) {
mkdir $name, 0755 or die "ERROR: mkdir $name: $!\n";
};
- init_target_tree $cfg, $probes, $tree->{probe}, $tree->{$prop}, "$name/$prop", $tree->{PROBE_CONF},$tree->{alerts},$tree->{alertee};
+ init_target_tree $cfg, $probes, $tree->{$prop}, "$name/$prop";
}
if ($prop eq 'host' and check_filter($cfg,$name)) {
# print "init $name\n";
@@ -450,7 +434,6 @@ sub enable_dynamic($$$$){
}
}
foreach my $prop ( keys %{$tree}) {
- next if $prop eq "PROBE_CONF";
enable_dynamic $cfg, $tree->{$prop},"$path$prop.",$email if ref $tree->{$prop} eq 'HASH';
}
};
@@ -467,7 +450,7 @@ sub target_menu($$$;$){
my @hashes;
foreach my $prop (sort { $tree->{$a}{_order} <=> $tree->{$b}{_order}}
- grep { ref $tree->{$_} eq 'HASH' and $_ ne "PROBE_CONF" }
+ grep { ref $tree->{$_} eq 'HASH' }
keys %{$tree}) {
push @hashes, $prop;
}
@@ -546,7 +529,7 @@ sub get_overview ($$$$){
POSIX::strftime($cfg->{Presentation}{overview}{strftime},
localtime(time)) : scalar localtime(time);
foreach my $prop (sort {$tree->{$a}{_order} <=> $tree->{$b}{_order}}
- grep { ref $tree->{$_} eq 'HASH' and $_ ne "PROBE_CONF" and defined $tree->{$_}{host}}
+ grep { ref $tree->{$_} eq 'HASH' and defined $tree->{$_}{host}}
keys %$tree) {
my $rrd = $cfg->{General}{datadir}.$dir."/$prop.rrd";
my $max = $cfg->{Presentation}{overview}{max_rtt} || "100000";
@@ -909,22 +892,20 @@ sub report_probes($$) {
}
}
-sub update_rrds($$$$$$);
-sub update_rrds($$$$$$) {
+sub update_rrds($$$$$);
+sub update_rrds($$$$$) {
my $cfg = shift;
my $probes = shift;
- my $probe = shift;
my $tree = shift;
my $name = shift;
my $justthisprobe = shift; # if defined, update only the targets probed by this probe
- $probe = $tree->{probe} if defined $tree->{probe};
+ my $probe = $tree->{probe};
my $probeobj = $probes->{$probe};
foreach my $prop (keys %{$tree}) {
- next if $prop eq "PROBE_CONF";
if (ref $tree->{$prop} eq 'HASH'){
- update_rrds $cfg, $probes, $probe, $tree->{$prop}, $name."/$prop", $justthisprobe;
+ update_rrds $cfg, $probes, $tree->{$prop}, $name."/$prop", $justthisprobe;
}
next if defined $justthisprobe and $probe ne $justthisprobe;
if ($prop eq 'host' and check_filter($cfg,$name)) {
@@ -1039,14 +1020,89 @@ ALERT
}
}
+sub _deepcopy {
+ # this handles circular references on consecutive levels,
+ # but breaks if there are any levels in between
+ my $what = shift;
+ return $what unless ref $what;
+ for (ref $what) {
+ /^ARRAY$/ and return [ map { $_ eq $what ? $_ : _deepcopy($_) } @$what ];
+ /^HASH$/ and return { map { $_ => $what->{$_} eq $what ?
+ $what->{$_} : _deepcopy($what->{$_}) } keys %$what };
+ /^CODE$/ and return $what; # we don't need to copy the subs
+ }
+ die "Cannot _deepcopy reference type @{[ref $what]}";
+}
+
sub get_parser () {
+ # The _dyn() stuff here is quite confusing, so here's a walkthrough:
+ # 1 Probe is defined in the Probes section
+ # 1.1 _dyn is called for the section to add the probe- and target-specific
+ # vars into the grammar for this section and its subsections (subprobes)
+ # 1.2 A _dyn sub is installed for all mandatory target-specific variables so
+ # that they are made non-mandatory in the Targets section if they are
+ # specified here. The %storedtargetvars hash holds this information.
+ # 1.3 If a probe section has any subsections (subprobes) defined, the main
+ # section turns into a template that just offers default values for
+ # the subprobes. Because of this a _dyn sub is installed for subprobe
+ # sections that makes any mandatory variables in the main section non-mandatory.
+ # 1.4 A similar _dyn sub as in 1.2 is installed for the subprobe target-specific
+ # variables as well.
+ # 2 Probe is selected in the Targets section top
+ # 2.1 _dyn is called for the section to add the probe- and target-specific
+ # vars into the grammar for this section and its subsections. Any _default
+ # values for the vars are removed, as they will be propagated from the Probes
+ # section.
+ # 2.2 Another _dyn sub is installed for the 'probe' variable in target subsections
+ # that behaves as 2.1
+ # 2.3 A _dyn sub is installed for the 'host' variable that makes the mandatory
+ # variables mandatory only in those sections that have a 'host' setting.
+ # 2.4 A _sub sub is installed for the 'probe' variable in target subsections that
+ # bombs out if 'probe' is defined after any variables that depend on the
+ # current 'probe' setting.
+
+
my $KEY_RE = '[-_0-9a-zA-Z]+';
my $KEYD_RE = '[-_0-9a-zA-Z.]+';
- my $TARGET =
- {
- _sections => [ ( "PROBE_CONF", "/$KEY_RE/" ) ],
- _vars => [ qw (probe menu title alerts note email host remark rawlog alertee) ],
+ my $PROBE_RE = '[a-z]*[A-Z][a-zA-Z]+';
+ my %knownprobes; # the probes encountered so far
+
+ # get a list of available probes for _dyndoc sections
+ my $probedir = find_probedir();
+ my $probelist;
+ die("Can't find probe module directory") unless defined $probedir;
+ opendir(D, $probedir) or die("opendir $probedir: $!");
+ for (readdir D) {
+ next unless s/\.pm$//;
+ next unless /^$PROBE_RE/;
+ $probelist->{$_} = "(See the separate module documentation for details about each variable.)";
+ }
+ closedir D;
+
+ # The target-specific vars of each probe
+ # We need to store them to relay information from Probes section to Target section
+ # see 1.2 above
+ my %storedtargetvars;
+
+ # the part of target section syntax that doesn't depend on the selected probe
+ my %TARGETCOMMON; # predeclare self-referencing structures
+ # the common variables
+ my $TARGETCOMMONVARS = [ qw (probe menu title alerts note email host remark rawlog alertee) ];
+ %TARGETCOMMON =
+ (
+ _vars => $TARGETCOMMONVARS,
+ _inherited=> [ qw (probe alerts alertee) ],
+ _sections => [ "/$KEY_RE/" ],
+ _recursive=> [ "/$KEY_RE/" ],
+ _sub => sub {
+ my $val = shift;
+ return "PROBE_CONF sections are neither needed nor supported any longer. Please see the smokeping_upgrade document."
+ if $val eq 'PROBE_CONF';
+ return undef;
+ },
+ "/$KEY_RE/" => {},
_order => 1,
+ _varlist => 1,
_doc => <<DOC,
Each target section can contain information about a host to monitor as
well as further target sections. Most variables have already been
@@ -1145,24 +1201,58 @@ DOC
If you want to have alerts for this target and all targets below it go to a particular address
on top of the address already specified in the alert, you can add it here. This can be a comma separated list of items.
DOC
-
- };
-
- $TARGET->{ "/$KEY_RE/" } = $TARGET;
-
- my $PROBEVARS = {
- _vars => [ "/$KEYD_RE/" ],
- _doc => <<DOC,
-Probe specific variables.
-DOC
- "/$KEYD_RE/" => { _doc => <<DOC },
-Should be found in the documentation of the
-corresponding probe. The values get propagated to those child
-nodes using the same Probe.
-DOC
- };
-
- $TARGET->{PROBE_CONF} = $PROBEVARS;
+ probe => {
+ _sub => sub {
+ my $val = shift;
+ my $varlist = shift;
+ return "probe $val missing from the Probes section"
+ unless $knownprobes{$val};
+ my %commonvars;
+ $commonvars{$_} = 1 for @{$TARGETCOMMONVARS};
+ delete $commonvars{host};
+ # see 2.4 above
+ return "probe must be defined before the host or any probe variables"
+ if grep { not exists $commonvars{$_} } @$varlist;
+
+ return undef;
+ },
+ _dyn => sub {
+ # this generates the new syntax whenever a new probe is selected
+ # see 2.2 above
+ my ($name, $val, $grammar) = @_;
+
+ my $targetvars = _deepcopy($storedtargetvars{$val});
+ my @mandatory = @{$targetvars->{_mandatory}};
+ delete $targetvars->{_mandatory};
+ my @targetvars = sort keys %$targetvars;
+
+ # the default values for targetvars are only used in the Probes section
+ delete $targetvars->{$_}{_default} for @targetvars;
+
+ # we replace the current grammar altogether
+ %$grammar = ( %TARGETCOMMON, %$targetvars );
+ $grammar->{_vars} = [ @{$grammar->{_vars}}, @targetvars ];
+
+ # the subsections differ only in that they inherit their vars from here
+ my $g = _deepcopy($grammar);
+ $grammar->{"/$KEY_RE/"} = $g;
+ push @{$g->{_inherited}}, @targetvars;
+
+ # this makes the variables mandatory only in those sections
+ # where 'host' is defined. (We must generate this dynamically
+ # as the mandatory list isn't visible earlier.)
+ # see 2.3 above
+
+ my $mandatorysub = sub {
+ my ($name, $val, $grammar) = @_;
+ $grammar->{_mandatory} = [ @mandatory ];
+ };
+ $grammar->{host} = _deepcopy($grammar->{host});
+ $grammar->{host}{_dyn} = $mandatorysub;
+ $g->{host}{_dyn} = $mandatorysub;
+ },
+ },
+ );
my $INTEGER_SUB = {
_sub => sub {
@@ -1185,73 +1275,145 @@ DOC
}
};
+ # grammar for the ***Probes*** section
my $PROBES = {
- _doc => <<DOC,
-Each module can take specific configuration information from this area. The jumble of letters above is a regular expression defining legal module names.
-DOC
- _vars => [ "step", "offset", "pings", "/$KEYD_RE/" ],
- "/$KEYD_RE/" => { _doc => 'Each module defines which
-variables it wants to accept. So this expression here just defines legal variable names.'},
- "step" => { %$INTEGER_SUB,
- _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'",
- _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" => {
- %$INTEGER_SUB,
- _doc => <<DOC},
-How many pings should be sent to each target, if different from the global
-value specified in the Database section. Some probes (those derived from
-basefork.pm, ie. most except the FPing variants) will even let this be
-overridden target-specifically in the PROBE_CONF section (see the
-basefork documentation for details). 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 => <<DOC,
+Each module can take specific configuration information from this
+area. The jumble of letters above is a regular expression defining legal
+module names.
+
+See the documentation of each module for details about its variables.
DOC
- }; # $PROBES
+ _sections => [ "/$PROBE_RE/" ],
- my $PROBESTOP = {};
- %$PROBESTOP = %$PROBES;
- $PROBESTOP->{_sections} = ["/$KEY_RE/"];
- $PROBESTOP->{"/$KEY_RE/"} = $PROBES;
- for (qw(step offset pings)) {
- # we need a deep copy of these
- my %h = %{$PROBESTOP->{$_}};
- $PROBES->{$_} = \%h;
- delete $PROBES->{$_}{_doc}
- }
- $PROBES->{_doc} = <<DOC;
+ # this adds the probe-specific variables to the grammar
+ # see 1.1 above
+ _dyn => sub {
+ my ($re, $name, $grammar) = @_;
+
+ # load the probe module
+ my $class = "probes::$name";
+ eval "require $class";
+ die "require $class failed: $@\n" if $@;
+
+ # modify the grammar
+ my $probevars = $class->probevars;
+ my $targetvars = $class->targetvars;
+ $storedtargetvars{$name} = $targetvars;
+
+ my @mandatory = @{$probevars->{_mandatory}};
+ my @targetvars = sort grep { $_ ne '_mandatory' } keys %$targetvars;
+ for (@targetvars) {
+ next if $_ eq '_mandatory';
+ delete $probevars->{$_};
+ }
+ my @probevars = sort grep { $_ ne '_mandatory' } keys %$probevars;
+
+ $grammar->{_vars} = [ @probevars , @targetvars ];
+ $grammar->{_mandatory} = [ @mandatory ];
+
+ # do it for probe instances in subsections too
+ my $g = $grammar->{"/$KEY_RE/"};
+ for (@probevars) {
+ $grammar->{$_} = $probevars->{$_};
+ %{$g->{$_}} = %{$probevars->{$_}};
+ # this makes the reference manual a bit less cluttered
+ delete $g->{$_}{_doc};
+ delete $g->{$_}{_example};
+ delete $grammar->{$_}{_doc};
+ delete $grammar->{$_}{_example};
+ }
+ # make any mandatory variable specified here non-mandatory in the Targets section
+ # see 1.2 above
+ my $sub = sub {
+ my ($name, $val, $grammar) = shift;
+ $targetvars->{_mandatory} = [ grep { $_ ne $name } @{$targetvars->{_mandatory}} ];
+ };
+ for my $var (@targetvars) {
+ %{$grammar->{$var}} = %{$targetvars->{$var}};
+ %{$g->{$var}} = %{$targetvars->{$var}};
+ # this makes the reference manual a bit less cluttered
+ delete $grammar->{$var}{_example};
+ delete $g->{$var}{_doc};
+ delete $g->{$var}{_example};
+ # (note: intentionally overwrite _doc)
+ $grammar->{$var}{_doc} = " (This variable can be overridden target-specifically in the Targets section.)";
+ $grammar->{$var}{_dyn} = $sub
+ if grep { $_ eq $var } @{$targetvars->{_mandatory}};
+ }
+ $g->{_vars} = [ @probevars, @targetvars ];
+ $g->{_inherited} = $g->{_vars};
+ $g->{_mandatory} = [ @mandatory ];
+
+ # the special value "_template" means we don't know yet if
+ # there will be any instances of this probe
+ $knownprobes{$name} = "_template";
+
+ $g->{_dyn} = sub {
+ # 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
+ # after the whole config tree is read, so we can fiddle
+ # here with "_mandatory" all we want.
+ # see 1.3 above
+
+ my ($re, $subprobename, $subprobegrammar) = @_;
+ delete $grammar->{_mandatory};
+ # the parent section doesn't define a valid probe anymore
+ delete $knownprobes{$name}
+ if $knownprobes{$name} eq '_template';
+ # this also keeps track of the real module name for each subprobe,
+ # should we ever need it
+ $knownprobes{$subprobename} = $name;
+ my $subtargetvars = _deepcopy($targetvars);
+ $storedtargetvars{$subprobename} = $subtargetvars;
+ # make any mandatory variable specified here non-mandatory in the Targets section
+ # see 1.4 above
+ my $sub = sub {
+ my ($name, $val, $grammar) = shift;
+ $subtargetvars->{_mandatory} = [ grep { $_ ne $name } @{$subtargetvars->{_mandatory}} ];
+ };
+ for my $var (@targetvars) {
+ $subprobegrammar->{$var}{_dyn} = $sub
+ if grep { $_ eq $var } @{$subtargetvars->{_mandatory}};
+ }
+ }
+ },
+ _dyndoc => $probelist, # all available probes
+ _sections => [ "/$KEY_RE/" ],
+ "/$KEY_RE/" => {
+ _doc => <<DOC,
You can define multiple instances of the same probe with subsections.
These instances can have different values for their variables, so you
can eg. have one instance of the FPing probe with packet size 1000 and
-step 30 and another instance with packet size 64 and step 300.
+step 300 and another instance with packet size 64 and step 30.
The name of the subsection determines what the probe will be called, so
you can write descriptive names for the probes.
If there are any subsections defined, the main section for this probe
will just provide default parameter values for the probe instances, ie.
it will not become a probe instance itself.
+
+The example above would be written like this:
+
+ *** Probes ***
+
+ + FPing
+ # this value is common for the two subprobes
+ binary = /usr/bin/fping
+
+ ++ FPingLarge
+ packetsize = 1000
+ step = 300
+
+ ++ FPingSmall
+ packetsize = 64
+ step = 30
+
DOC
+ },
+ }; # $PROBES
my $parser = ISG::ParseConfig->new
(
@@ -1454,8 +1616,7 @@ DOC
How many pings should be sent to each target. Suggested: 20 pings.
This can be overridden by each probe. Some probes (those derived from
basefork.pm, ie. most except the FPing variants) will even let this
-be overridden target-specifically in the PROBE_CONF section (see the
-basefork documentation for details). Note that the number of pings in
+be overridden target-specifically. 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.
@@ -1780,9 +1941,11 @@ DOC
}, #present
Probes => { _sections => [ "/$KEY_RE/" ],
_doc => <<DOC,
-The Probes Section configures Probe modules. Probe modules integrate an external ping command into SmokePing. Check the documentation of the FPing module for configuration details.
+The Probes Section configures Probe modules. Probe modules integrate
+an external ping command into SmokePing. Check the documentation of each
+module for more information about it.
DOC
- "/$KEY_RE/" => $PROBESTOP,
+ "/$KEY_RE/" => $PROBES,
},
Alerts => {
_doc => <<DOC,
@@ -1916,12 +2079,54 @@ DOC
_vars => [ qw(probe menu title remark alerts) ],
_mandatory => [ qw(probe menu title) ],
_order => 1,
- _sections => [ ( "PROBE_CONF", "/$KEY_RE/" ) ],
- probe => { _doc => <<DOC },
+ _sections => [ "/$KEY_RE/" ],
+ _recursive => [ "/$KEY_RE/" ],
+ "/$KEY_RE/" => \%TARGETCOMMON, # this is just for documentation, _dyn() below replaces it
+ probe => {
+ _doc => <<DOC,
The name of the probe module to be used for this host. The value of
this variable gets propagated
DOC
- PROBE_CONF => $PROBEVARS,
+ _sub => sub {
+ my $val = shift;
+ return "probe $val missing from the Probes section"
+ unless $knownprobes{$val};
+ return undef;
+ },
+ # create the syntax based on the selected probe.
+ # see 2.1 above
+ _dyn => sub {
+ my ($name, $val, $grammar) = @_;
+
+ my $targetvars = _deepcopy($storedtargetvars{$val});
+ my @mandatory = @{$targetvars->{_mandatory}};
+ delete $targetvars->{_mandatory};
+ my @targetvars = sort keys %$targetvars;
+ for (@targetvars) {
+ # the default values for targetvars are only used in the Probes section
+ delete $targetvars->{$_}{_default};
+ $grammar->{$_} = $targetvars->{$_};
+ }
+ push @{$grammar->{_vars}}, @targetvars;
+ my $g = { %TARGETCOMMON, %{_deepcopy($targetvars)} };
+ $grammar->{"/$KEY_RE/"} = $g;
+ $g->{_vars} = [ @{$g->{_vars}}, @targetvars ];
+ $g->{_inherited} = [ @{$g->{_inherited}}, @targetvars ];
+ # this makes the reference manual a bit less cluttered
+ delete $grammar->{$_}{_doc} for @targetvars;
+ delete $grammar->{$_}{_example} for @targetvars;
+ delete $g->{$_}{_doc} for @targetvars;
+ delete $g->{$_}{_example} for @targetvars;
+ # make the mandatory variables mandatory only in sections
+ # with 'host' defined
+ # see 2.3 above
+ $g->{host}{_dyn} = sub {
+ my ($name, $val, $grammar) = @_;
+ $grammar->{_mandatory} = [ @mandatory ];
+ };
+ }, # _dyn
+ _dyndoc => $probelist, # all available probes
+ }, #probe
menu => { _doc => <<DOC },
Menu entry for this section. If not set this will be set to the hostname.
DOC
@@ -1941,9 +2146,8 @@ DOC
An optional remark on the current section. It gets displayed on the webpage.
DOC
- "/$KEY_RE/" => $TARGET
}
-
+
}
);
return $parser;
@@ -2099,7 +2303,7 @@ sub load_cfg ($) {
$probes = load_probes $cfg;
$cfg->{__probes} = $probes;
init_alerts $cfg if $cfg->{Alerts};
- init_target_tree $cfg, $probes, $cfg->{Targets}{probe}, $cfg->{Targets}, $cfg->{General}{datadir}, $cfg->{Targets}{PROBE_CONF},$cfg->{Targets}{alerts},undef;
+ init_target_tree $cfg, $probes, $cfg->{Targets}, $cfg->{General}{datadir};
}
}
@@ -2107,7 +2311,7 @@ sub load_cfg ($) {
sub makepod ($){
my $parser = shift;
my $e='=';
- print <<POD;
+ my $retval = <<POD;
${e}head1 NAME
@@ -2127,14 +2331,17 @@ ParseConfig module. Read all about it in L<ISG::ParseConfig>.
The Configuration file has a tree-like structure with section headings at
various levels. It also contains variable assignments and tables.
+Warning: this manual is rather long. See the smokeping_examples document
+for simple configuration examples.
+
${e}head1 REFERENCE
The text below describes the syntax of the SmokePing configuration file.
POD
- print $parser->makepod;
- print <<POD;
+ $retval .= $parser->makepod;
+ $retval .= <<POD;
${e}head1 COPYRIGHT
@@ -2165,8 +2372,6 @@ Tobias Oetiker E<lt>tobi\@oetiker.chE<gt>
${e}cut
POD
- exit 0;
-
}
sub cgi ($) {
@@ -2270,19 +2475,75 @@ sub pages ($) {
load_cfg($config);
makestaticpages($cfg, undef);
}
-
-sub main ($) {
+
+sub pod2man {
+ my $string = shift;
+ my $pid = open(P, "-|");
+ if ($pid) {
+ pod2usage(-verbose => 2, -input => \*P);
+ exit 0;
+ } else {
+ print $string;
+ exit 0;
+ }
+}
+
+sub probedoc {
+ my $class = shift;
+ my $do_man = shift;
+ eval "require $class";
+ die("Failed to load $class: $@") if $@;
+ if ($do_man) {
+ pod2man($class->pod);
+ } else {
+ print $class->pod;
+ }
+ exit 0;
+}
+
+sub verify_cfg {
+ my $cfgfile = shift;
+ get_config(get_parser, $cfgfile);
+ print "Configuration file '$cfgfile' syntax OK.\n";
+}
+
+sub main (;$) {
$cgimode = 0;
umask 022;
- my $cfgfile = shift;
+ my $defaultcfg = shift;
$opt{filter}=[];
- GetOptions(\%opt, 'version', 'email', ,'man','help','logfile=s','static-pages:s', 'debug-daemon',
- 'nosleep', 'makepod','debug','restart', 'filter=s', 'nodaemon|nodemon') or pod2usage(2);
+ GetOptions(\%opt, 'version', 'email', 'man:s','help','logfile=s','static-pages:s', 'debug-daemon',
+ 'nosleep', 'makepod:s','debug','restart', 'filter=s', 'nodaemon|nodemon',
+ 'config=s', 'check', 'gen-examples') or pod2usage(2);
if($opt{version}) { print "$RCS_VERSION\n"; exit(0) };
- if($opt{man}) { pod2usage(-verbose => 2); exit 0 };
+ if(exists $opt{man}) {
+ if ($opt{man}) {
+ if ($opt{man} eq 'smokeping_config') {
+ pod2man(makepod(get_parser));
+ } else {
+ probedoc($opt{man}, 'do_man');
+ }
+ } else {
+ pod2usage(-verbose => 2);
+ }
+ exit 0;
+ }
if($opt{help}) { pod2usage(-verbose => 1); exit 0 };
- if($opt{makepod}) { makepod(get_parser) ; exit 0};
+ if(exists $opt{makepod}) {
+ if ($opt{makepod} and $opt{makepod} ne 'smokeping_config') {
+ probedoc($opt{makepod});
+ } else {
+ print makepod(get_parser);
+ }
+ exit 0;
+ }
+ if (exists $opt{'gen-examples'}) {
+ Smokeping::Examples::make($opt{check});
+ exit 0;
+ }
initialize_debuglog if $opt{debug} or $opt{'debug-daemon'};
+ my $cfgfile = $opt{config} || $defaultcfg;
+ if(defined $opt{'check'}) { verify_cfg($cfgfile); 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 };
@@ -2422,7 +2683,7 @@ KID:
}
my $now = time;
run_probes $probes, $myprobe; # $myprobe is undef if running without 'concurrentprobes'
- update_rrds $cfg, $probes, $cfg->{Targets}{probe}, $cfg->{Targets}, $cfg->{General}{datadir}, $myprobe;
+ update_rrds $cfg, $probes, $cfg->{Targets}, $cfg->{General}{datadir}, $myprobe;
exit 0 if $opt{debug};
my $runtime = time - $now;
if ($runtime > $step) {
@@ -2599,6 +2860,8 @@ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
Tobias Oetiker E<lt>tobi\@oetiker.chE<gt>
+Niko Tyni E<lt>ntyni@iki.fiE<gt>
+
=cut
# Emacs Configuration
diff --git a/lib/Smokeping/Examples.pm b/lib/Smokeping/Examples.pm
new file mode 100644
index 0000000..5adbfff
--- /dev/null
+++ b/lib/Smokeping/Examples.pm
@@ -0,0 +1,633 @@
+# -*- perl -*-
+package Smokeping::Examples;
+use strict;
+use Smokeping;
+
+=head1 NAME
+
+Smokeping::Examples - A module for generating the smokeping_examples document
+
+=head1 OVERVIEW
+
+This module generates the smokeping_examples document and the example
+configuration files distributed with Smokeping. It is supposed to be
+invoked from the smokeping distribution top directory, as it will need
+the C<etc/config.dist> template configuration file and will create files
+in the directories C<doc> and C<doc/examples>.
+
+=head1 DESCRIPTION
+
+The entry point to the module is the C<make> subroutine. It takes one optional
+parameter, C<check>, that makes the module run a syntax check for all the
+created example configuration files.
+
+=head1 BUGS
+
+This module uses more or less internal functions from C<Smokeping.pm>. It's a
+separate module only because the latter is much too big already.
+
+It should be possible to include POD markup in the configuration explanations
+and have this module filter them away for the config files.
+
+=head1 COPYRIGHT
+
+Copyright 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 AUTHOR
+
+Niko Tyni <ntyni@iki.fi>
+
+=cut
+
+use strict;
+
+sub read_config_template {
+ my $file = "etc/config.dist";
+ my $h = {
+ common => "", # everything up to the Probes section
+ probes => "", # the Probes section, without the *** Probes *** line
+ targets => "", # the Targets section, without the *** Targets *** line
+ };
+ open(F, "<$file") or die("open template configuration file $file for reading: $!");
+ my %found;
+ while (<F>) {
+ /\*\*\*\s*(Probes|Targets)\s*\*\*\*/ and $found{$1} = 1, next;
+ $h->{common} .= $_ and next unless $found{Probes};
+ $h->{probes} .= $_ and next unless $found{Targets};
+ $h->{targets} .= $_;
+ }
+ close F;
+ return $h;
+}
+
+sub prologue {
+ my $e = "=";
+ return <<DOC;
+${e}head1 NAME
+
+smokeping_examples - Examples of Smokeping configuration
+
+${e}head1 OVERVIEW
+
+This document provides some examples of Smokeping configuration files.
+All the examples can be found in the C<examples> directory in the
+Smokeping documentation. Note that the DNS names in the examples are
+non-functional.
+
+Details of the syntax and all the variables are found in the
+smokeping_config reference document and in the documentation of the
+corresponding probe, if applicable.
+
+This manual is automatically generated from the Smokeping source code.
+
+${e}head1 DESCRIPTION
+
+Currently the examples differ only in the C<Probes> and C<Targets>
+sections. The other sections are taken from the C<etc/config.dist>
+configuration template in the Smokeping distribution so that the example
+files are complete.
+
+If you would like to provide more examples, document the other sections
+or enhance the existing examples, please do so, preferably by sending
+the proposed changes to the smokeping-users mailing list.
+
+DOC
+}
+
+sub epilogue {
+ my $e = "=";
+ return <<DOC;
+
+${e}head1 COPYRIGHT
+
+Copyright 2005 by Niko Tyni.
+
+${e}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.
+
+${e}head1 AUTHOR
+
+Niko Tyni <ntyni\@iki.fi>
+
+${e}head1 SEE ALSO
+
+The other Smokeping documents, especially smokeping_config.
+DOC
+}
+
+sub make {
+ print "Generating example files...\n";
+ my $check = shift; # check the syntax of the generated config files
+ my $template = read_config_template();
+ my $examples = examples($template);
+ my $manual = prologue();
+ for my $ex (sort { $examples->{$a}{order} <=> $examples->{$b}{order} } keys %$examples) {
+ my $h = $examples->{$ex};
+ $manual .= "\n=head2 Example $h->{order}: config.$ex\n\n"
+ . genpod($h);
+ my $cfgfile = "doc/examples/config.$ex";
+ print "\t$cfgfile ...\n";
+ writecfg($cfgfile, $template, $h);
+ if ($check) {
+ local $Smokeping::cfg = undef;
+ eval {
+ Smokeping::verify_cfg($cfgfile);
+ };
+ die("Syntax check for $cfgfile failed: $@") if $@;
+ }
+ }
+ $manual .= epilogue();
+ writemanual($manual);
+ print "done.\n";
+}
+
+sub writemanual {
+ my $text = shift;
+ my $filename = "doc/smokeping_examples.pod";
+ print "\t$filename ...\n";
+ open(F, ">$filename") or die("open $filename for writing: $!");
+ print F $text;
+ close F;
+}
+
+sub genpod {
+ my $h = shift;
+ my $text = "";
+ $text .= "=over\n\n";
+ $text .= "=item Probe configuration\n\n";
+ $text .= " *** Probes ***\n";
+ $text .= join("\n", map { " $_" } split(/\n/, $h->{probes}));
+ $text .= "\n\n=item Probe explanation\n\n";
+ $text .= $h->{probedoc};
+ $text .= "\n\n=item Target configuration\n\n";
+ $text .= " *** Targets ***\n";
+ $text .= join("\n", map { " $_" } split(/\n/, $h->{targets}));
+ $text .= "\n\n=item Target explanation\n\n";
+ $text .= $h->{targetdoc};
+ $text .= "\n\n=back\n\n";
+ return $text;
+}
+
+sub writecfg {
+ my $file = shift;
+ my $template = shift;
+ my $h = shift;
+ open(F, ">$file") or die("open $file for writing: $!");
+ print F <<DOC;
+# This Smokeping example configuration file was automatically generated.
+#
+# Everything up to the Probes section is derived from a common template file.
+# See the Probes and Targets sections for the actual example.
+#
+# This example is included in the smokeping_examples document.
+
+DOC
+ print F $template->{common};
+ print F "# (The actual example starts here.)\n";
+ print F "\n *** Probes ***\n\n";
+ print F join("\n", map { "# $_" } split(/\n/, $h->{probedoc}));
+ print F "\n\n";
+ print F $h->{probes};
+ print F "\n *** Targets ***\n\n";
+ print F join("\n", map { "# $_" } split(/\n/, $h->{targetdoc}));
+ print F "\n\n";
+ print F $h->{targets};
+ close F;
+}
+
+sub examples {
+ my $template = shift;
+ return {
+ simple => {
+ order => 1,
+ probes => <<DOC,
++FPing
+binary = /usr/bin/fping
+DOC
+ targets => <<DOC,
+probe = FPing
+
+menu = Top
+title = Network Latency Grapher
+remark = Welcome to this SmokePing website.
+
++ mysite1
+menu = Site 1
+title = Hosts in Site 1
+
+++ myhost1
+host = myhost1.mysite1.example
+++ myhost2
+host = myhost2.mysite1.example
+
++ mysite2
+menu = Site 2
+title = Hosts in Site 2
+
+++ myhost3
+host = myhost3.mysite2.example
+++ myhost4
+host = myhost4.mysite2.example
+DOC
+ probedoc => <<DOC,
+Here we have just one probe, fping, pinging four hosts.
+
+The fping probe is using the default parameters, some of them supplied
+from the Database section ("step" and "pings"), and some of them by
+the probe module.
+DOC
+ targetdoc => <<DOC,
+The hosts are located in two sites of two hosts each, and the
+configuration has been divided to site sections ('+') and host subsections
+('++') accordingly.
+DOC
+ }, # simple
+ "multiple-probes" => {
+ order => 2,
+ probes => <<DOC,
++ FPing
+binary = /usr/bin/fping
+packetsize = 1000
+
++ DNS
+binary = /usr/bin/dig
+lookup = name.example
+pings = 5
+step = 180
+
++ EchoPingHttp
+pings = 5
+url = /test-url
+DOC
+ targets => <<DOC,
+probe = FPing
+menu = Top
+title = Network Latency Grapher
+remark = Welcome to this SmokePing website.
+
++ network
+menu = Net latency
+title = Network latency (ICMP pings)
+
+++ myhost1
+host = myhost1.example
+++ myhost2
+host = myhost2.example
+
++ services
+menu = Service latency
+title = Service latency (DNS, HTTP)
+
+++ DNS
+probe = DNS
+menu = DNS latency
+title = Service latency (DNS)
+
++++ dns1
+host = dns1.example
+
++++ dns2
+host = dns2.example
+
+++ HTTP
+menu = HTTP latency
+title = Service latency (HTTP)
+
++++ www1
+host = www1.example
+
++++ www2
+host = www2.example
+DOC
+ probedoc => <<DOC,
+Here we have three probes: FPing for the regular ICMP pings,
+DNS for name server latency measurement and EchoPingHttp
+for web servers.
+
+The FPing probe runs with the default parameters, except that the ICMP
+packet size is 1000 bytes instead of the default 56 bytes.
+
+The DNS and EchoPingHttp probes have been configured to be a bit more
+gentle with the servers, as they only do 5 queries (pings) instead of the
+default 20 (or whatever is specified in the Database section). However,
+DNS queries are made more often: 5 queries every 3 minutes instead of
+every 5 minutes.
+DOC
+ targetdoc => <<DOC,
+The target tree has been divided by the probe used. This does not have
+to be the case: every target (sub)section can use a different probe,
+and the same probe can be used in different parts of the config tree.
+DOC
+ }, # multiple-probes
+ "fping-instances" => {
+ order => 3,
+ probes => <<DOC,
++ FPing
+binary = /usr/bin/fping
+
+++ FPingNormal
+offset = 0%
+
+++ FPingLarge
+packetsize = 5000
+offset = 50%
+DOC
+ probedoc => <<DOC,
+This example demonstrates the concept of probe instances. The FPingLarge
+and FPingNormal probes are independent of each other, they just use
+the same module, FPing. FPingNormal uses the default parameters, and
+so does FPingLarge except for the 5 kilobyte packetsize. Both use the
+same fping binary, and its path is configured FPing top section.
+
+The 'offset' parameters make sure the probes don't run at the same time -
+FPingNormal is run every 'full' 5 minutes (eg. 8:00, 8:05, 8:10 and so on,
+in wallclock time) while FPingLarge is run halfway through these intervals
+(eg. 8:02:30, 8:07:30 etc.)
+
+The top FPing section does not define a probe in itself because it
+has subsections. If we really wanted to have one probe named "FPing",
+we could do so by making a subsection by that name.
+DOC
+ targets => <<DOC,
+probe = FPingNormal
+menu = Top
+title = Network Latency Grapher
+remark = Welcome to this SmokePing website.
+
++ network
+menu = Net latency
+title = Network latency (ICMP pings)
+
+++ myhost1
+menu = myhost1
+title = ICMP latency for myhost1
+
++++ normal
+title = Normal packetsize (56 bytes)
+probe = FPingNormal
+host = myhost1.example
+
++++ large
+title = Large packetsize (5000 bytes)
+probe = FPingLarge
+host = myhost1.example
+
+++ myhost2
+menu = myhost2
+title = ICMP latency for myhost2
+
++++ normal
+title = Normal packetsize (56 bytes)
+probe = FPingNormal
+host = myhost2.example
+
++++ large
+title = Large packetsize (5000 bytes)
+probe = FPingLarge
+host = myhost2.example
+DOC
+ targetdoc => <<DOC,
+The target section shows two host, myhost1.example and myhost2.example,
+being pinged with two differently sized ICMP packets. This time the tree
+is divided by the target host rather than the probe.
+DOC
+ }, # fping-instances
+ "targetvars-with-Curl" => {
+ order => 4,
+ probes => <<DOC,
++ Curl
+# probe-specific variables
+binary = /usr/bin/curl
+step = 60
+
+# a default for this target-specific variable
+urlformat = http://%host/
+DOC
+ probedoc => <<DOC,
+This example explains the difference between probe- and target-specific
+variables. We use the Curl probe for this.
+
+Every probe supports at least some probe-specific variables. The values
+of these variables are common to all the targets of the probe, and
+they can only be configured in the Probes section. In this case,
+the probe-specific variables are "binary" and "step".
+
+Target-specific variables are supported by most probes, the most notable
+exception being the FPing probe and its derivatives. Target-specific
+variables can have different values for different targets. They can be
+configured in both Probes and Targets sections. The values assigned in the
+Probes section function become default values that can be overridden
+in the Targets section.
+
+The documentation of each probe states which of its variables are
+probe-specific and which are target-specific.
+
+In this case the "urlformat" variable is a target-specific one. It is
+also quite uncommon, because it can contain a placeholder for the "host"
+variable in the Targets section. This is not a general feature, its
+usage is only limited to the "urlformat" variable and the "%host%" escape.
+
+(The reason why the FPing probe does not support target-specific variables
+is simply the fact that the fping program measures all its targets in one
+go, so they all have the same parameters. The other probes ping their targets
+one at a time.)
+DOC
+ targets => <<DOC,
+probe = Curl
+menu = Top
+title = Network Latency Grapher
+remark = Welcome to this SmokePing website.
+
++ HTTP
+menu = http
+title = HTTP latency
+
+++ myhost1
+menu = myhost1
+title = HTTP latency for myhost1
+host = myhost1.example
+
+++ myhost2
+menu = myhost2
+title = HTTP latency for myhost2
+host = myhost2.example
+
+++ myhost3
+menu = myhost3
+title = HTTP latency for myhost3 (port 8080!)
+host = myhost3.example
+urlformat = http://%host%:8080/
+
++ FTP
+menu = ftp
+title = FTP latency
+urlformat = ftp://%host%/
+
+++ myhost1
+menu = myhost1
+title = FTP latency for myhost1
+host = myhost1.example
+
+++ myhost2
+menu = myhost2
+title = FTP latency for myhost2
+host = myhost2.example
+DOC
+ targetsdoc => <<DOC,
+The target tree is divided into an HTTP branch and an FTP one.
+The servers "myhost1.example" and "myhost2.example" are probed
+in both. The third server, "myhost3.example", only has an HTTP
+server, and it's in a non-standard port (8080).
+
+The "urlformat" variable is specified for the whole FTP branch
+as "ftp://%host%/". For the HTTP branch, the default from the
+Probes section is used, except for myhost3, which overrides
+it to tag the port number into the URL.
+
+The myhost3 assignment could just as well have included the hostname
+verbatim (ie. urlformat = http://myhost3.example:8080/) instead of
+using the %host% placeholder, but the host variable would still have
+been required (even though it wouldn't have been used for anything).
+DOC
+ }, # targetvars-with-Curl
+ echoping => {
+ order => 5,
+ probes => <<DOC,
++ FPing
+binary = /usr/bin/fping
+
+# these expect to find echoping in /usr/bin
+# if not, you'll have to specify the location separately for each probe
+# + EchoPing # uses TCP or UDP echo (port 7)
+# + EchoPingDiscard # uses TCP or UDP discard (port 9)
+# + EchoPingChargen # uses TCP chargen (port 19)
++ EchoPingSmtp # SMTP (25/tcp) for mail servers
++ EchoPingHttps # HTTPS (443/tcp) for web servers
++ EchoPingHttp # HTTP (80/tcp) for web servers and caches
++ EchoPingIcp # ICP (3130/udp) for caches
+DOC
+ probedoc => <<DOC,
+This example shows most of the echoping-derived probes in action.
+DOC
+ targets => <<DOC,
+# default probe
+probe = FPing
+
+menu = Top
+title = Network Latency Grapher
+remark = Welcome to this SmokePing website.
+
++ MyServers
+
+menu = My Servers
+title = My Servers
+
+++ www-server
+menu = www-server
+title = Web Server (www-server) / ICMP
+# probe = FPing propagated from top
+host = www-server.example
+
++++ http
+menu = http
+title = Web Server (www-server) / HTTP
+probe = EchoPingHttp
+host = www-server.example
+# default url is /
+
++++ https
+menu = https
+title = Web Server (www-server) / HTTPS
+probe = EchoPingHttps
+host = www-server.example
+
+++ cache
+menu = www-cache
+title = Web Cache (www-cache) / ICMP
+host = www-cache.example
+
++++ http
+menu = http
+title = www-cache / HTTP
+probe = EchoPingHttp
+host = www-cache.example
+port = 8080 # use the squid port
+url = http://www.somehost.example/
+
++++ icp
+menu = icp
+title = www-cache / ICP
+probe = EchoPingIcp
+host = www-cache.example
+url = http://www.somehost.example/
+
+++ mail
+menu = mail-server
+title = Mail Server (mail-server) / ICMP
+host = mail-server.example
+
++++ smtp
+menu = mail-server / SMTP
+title = Mail Server (mail-server) / SMTP
+probe = EchoPingSmtp
+host = mail-server.example
+DOC
+ targetdoc => <<DOC,
+All the servers are pinged both with ICMP (the FPing probe)
+and their respective echoping probe. The proxy server, www-cache,
+is probed with both HTTP requests and ICP requests for the same
+URL.
+DOC
+ }, # echoping
+ template => {
+ order => 6, # last
+ probes => $template->{probes},
+ targets => $template->{targets},
+ probedoc => <<DOC,
+This is the template configuration file distributed with Smokeping.
+It is included in the examples as well for the sake of completeness.
+DOC
+ targetdoc => <<DOC,
+This is the template configuration file distributed with Smokeping.
+It is included in the examples as well for the sake of completeness.
+DOC
+ },
+ }; # return
+} # sub examples
+
+1;
diff --git a/lib/probes/AnotherDNS.pm b/lib/probes/AnotherDNS.pm
index 7acc36d..9649514 100644
--- a/lib/probes/AnotherDNS.pm
+++ b/lib/probes/AnotherDNS.pm
@@ -1,77 +1,16 @@
package probes::AnotherDNS;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::AnotherDNS - Alternate DNS Probe
-
-=head1 SYNOPSIS
-
- *** Probes ***
- + AnotherDNS
-
- *** Targets ***
- probe = AnotherDNS
- forks = 10
-
- + First
- menu = First
- title = First Target
- # ....
-
- ++ PROBE_CONF
- lookup = www.mozilla.org
-
-=head1 DESCRIPTION
-
-Like DNS, but uses Net::DNS and Time::HiRes instead of dig. This probe does
-*not* retry the request three times before it is considerd "lost", like dig and
-other resolver do by default. If operating as caching Nameserver, BIND (and
-maybe others) expect clients to retry the request if the answer is not in the
-cache. So, ask the nameserver for something that he is authorative for if you
-want measure the network packet loss correctly.
-
-If you have a really fast network and nameserver, you will notice that this
-probe reports the query time in microsecond resolution. :-)
-
-=over
-
-=item forks
-
-The number of concurrent processes to be run. See probes::basefork(3pm)
-for details.
-
-=back
-
-Supported target-level probe variables:
-
-=over
-
-=item lookup
-
-Name of the host to look up in the dns.
+This is a Smokeping probe module. Please use the command
-=item sleeptime
+C<smokeping -man probes::AnotherDNS>
-Time to sleep between two lookups in microseconds. Default is 500000.
+to view the documentation or the command
-=item recordtype
+C<smokeping -makepod probes::AnotherDNS>
-Record type to look up. Default is "A".
-
-=item timeout
-
-Timeout for a single request in seconds. Default is 5.
-
-=item port
-
-UDP Port to use. Default is 53. (Surprise!)
-
-=back
-
-
-=head1 AUTHOR
-
-Christoph Heine E<lt>Christoph.Heine@HaDiKo.DEE<gt>
+to generate the POD document.
=cut
@@ -91,10 +30,32 @@ use base qw(probes::basefork);
use IPC::Open3;
use Symbol;
use Carp;
-use Time::HiRes qw(usleep ualarm gettimeofday tv_interval);
+use Time::HiRes qw(sleep ualarm gettimeofday tv_interval);
use IO::Socket;
use IO::Select;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::AnotherDNS - Alternate DNS Probe
+DOC
+ description => <<DOC,
+Like DNS, but uses Net::DNS and Time::HiRes instead of dig. This probe does
+*not* retry the request three times before it is considerd "lost", like dig and
+other resolver do by default. If operating as caching Nameserver, BIND (and
+maybe others) expect clients to retry the request if the answer is not in the
+cache. So, ask the nameserver for something that he is authoritative for if you
+want measure the network packet loss correctly.
+
+If you have a really fast network and nameserver, you will notice that this
+probe reports the query time in microsecond resolution. :-)
+DOC
+ authors => <<'DOC',
+Christoph Heine <Christoph.Heine@HaDiKo.DE>
+DOC
+ }
+}
+
sub new($$$) {
my $proto = shift;
my $class = ref($proto) || $proto;
@@ -113,14 +74,10 @@ sub pingone ($) {
my $host = $target->{addr};
my $lookuphost = $target->{vars}{lookup};
- my $sleeptime = $target->{vars}{sleeptime};
+ my $mininterval = $target->{vars}{mininterval};
my $recordtype = $target->{vars}{recordtype};
my $timeout = $target->{vars}{timeout};
my $port = $target->{vars}{port};
- $recordtype = "A" unless defined $recordtype;
- $timeout = 5 unless defined $timeout;
- $port = 53 unless defined $port;
- $sleeptime = 500000 unless defined $sleeptime;
$lookuphost = $target->{addr} unless defined $lookuphost;
my $packet = Net::DNS::Packet->new( $lookuphost, $recordtype )->data;
@@ -133,18 +90,22 @@ sub pingone ($) {
my @times;
+ my $elapsed;
for ( my $run = 0 ; $run < $self->pings($target) ; $run++ ) {
+ if (defined $elapsed) {
+ my $timeleft = $mininterval - $elapsed;
+ sleep $timeleft if $timeleft > 0;
+ }
my $t0 = [gettimeofday];
$sock->send($packet);
my ($ready) = $sel->can_read($timeout);
my $t1 = [gettimeofday];
+ $elapsed = tv_interval( $t0, $t1 );
if ( defined $ready ) {
- my $time = tv_interval( $t0, $t1 );
- push @times, $time;
+ push @times, $elapsed;
my $buf = '';
$ready->recv( $buf, &Net::DNS::PACKETSZ );
}
- usleep($sleeptime);
}
@times =
map { sprintf "%.10e", $_ } sort { $a <=> $b } grep { $_ ne "-" } @times;
@@ -152,5 +113,45 @@ sub pingone ($) {
return @times;
}
+sub probevars {
+ my $class = shift;
+ my $h = $class->SUPER::probevars;
+ delete $h->{timeout};
+ return $h;
+}
+
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ lookup => {
+ _doc => <<DOC,
+Name of the host to look up in the dns.
+DOC
+ _example => 'www.example.org',
+ },
+ mininterval => {
+ _doc => <<DOC,
+Minimum time between sending two lookup queries in (possibly fractional) seconds.
+DOC
+ _default => .5,
+ _re => '(\d*\.)?\d+',
+ },
+ recordtype => {
+ _doc => 'Record type to look up.',
+ _default => 'A',
+ },
+ timeout => {
+ _doc => 'Timeout for a single request in seconds.',
+ _default => 5,
+ _re => '\d+',
+ },
+ port => {
+ _doc => 'The UDP Port to use.',
+ _default => 53,
+ _re => '\d+',
+ },
+ });
+}
+
1;
diff --git a/lib/probes/AnotherSSH.pm b/lib/probes/AnotherSSH.pm
index bb1a8bb..1de6644 100644
--- a/lib/probes/AnotherSSH.pm
+++ b/lib/probes/AnotherSSH.pm
@@ -1,105 +1,41 @@
package probes::AnotherSSH;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::AnotherSSH - Another SSH probe
-
-=head1 SYNOPSIS
-
- *** Probes ***
- + AnotherSSH
-
- *** Targets ***
- probe = AnotherSSH
- forks = 10
-
- + First
- menu = First
- title = First Target
- # ....
-
- ++ PROBE_CONF
- greeting = SSH-Latecy-Measurement-Sorry-for-the-logfile-entry
- sleeptime = 500000
- interval = established
- timeout = 5
-
-=head1 DESCRIPTION
-
-Latency measurement using SSH. This generates Logfile messages on the other
-Host, so get permission from the owner first!
-
-=over
-
-=item forks
-
-The number of concurrent processes to be run. See probes::basefork(3pm)
-for details.
-
-=back
-
-Supported target-level probe variables:
-
-=over
-
-=item greeting
-
-Greeting string to send to the SSH Server. This will appear in the Logfile.
-Use this to make clear, who you are and what you are doing to avoid confusion.
-
-Also, don't use something that is a valid version string. This probe assumes
-that the connection gets terminated because of protocol mismatch.
-
-=item sleeptime
-
-Time to sleep between two measurements in microsends. Default is 500000.
-
-=item interval
-
-The interval to measure
-
-=over
-
-=item connect
-
-Interval between connect() and the greeting string from the host.
-
-=item established
-
-Interval between our greeting message and the end of the connection
-because of Protocol mismatch. This is the default.
-
-=item complete
-
-From connect() to the end of the connection.
-
-=back
-
-=item timeout
-
-Timeout for the connection. Default is 5.
-
-=item port
-
-Connect to this port. Default is 22.
+This is a Smokeping probe module. Please use the command
-=back
+C<smokeping -man probes::AnotherSSH>
+to view the documentation or the command
-=head1 AUTHOR
+C<smokeping -makepod probes::AnotherSSH>
-Christoph Heine E<lt>Christoph.Heine@HaDiKo.DEE<gt>
+to generate the POD document.
=cut
use strict;
use base qw(probes::basefork);
use Carp;
-use Time::HiRes qw(usleep ualarm gettimeofday tv_interval);
+use Time::HiRes qw(sleep ualarm gettimeofday tv_interval);
use IO::Select;
use Socket;
use Fcntl;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::AnotherSSH - Another SSH probe
+DOC
+ description => <<DOC,
+Latency measurement using SSH. This generates Logfile messages on the other
+Host, so get permission from the owner first!
+DOC
+ authors => <<'DOC',
+Christoph Heine <Christoph.Heine@HaDiKo.DE>
+DOC
+ }
+}
sub new($$$) {
my $proto = shift;
@@ -120,34 +56,30 @@ sub pingone ($) {
my $host = $target->{addr};
# Time
- my $sleeptime = $target->{vars}{sleeptime};
- $sleeptime = 500000 unless defined $sleeptime;
+ my $mininterval = $target->{vars}{mininterval};
# Our greeting string.
my $greeting = $target->{vars}{greeting};
- $greeting = "SSH-Latency-Measurement-Sorry-for-this-logmessage"
- unless defined $greeting;
# Interval to measure
my $interval = $target->{vars}{interval};
- $interval = "established" unless defined $interval;
- if(not ( $interval eq "connect" or $interval eq "established" or $interval eq "complete")) {
- $self->do_debug("Invalid interval parameter");
- return undef;
- }
# Connect to this port.
my $port = $target->{vars}{port};
- $port = 22 unless defined $port;
#Timeout for the select() calls.
my $timeout = $target->{vars}{timeout};
- $timeout = 5 unless defined $timeout;
my @times; # Result times
+ my $t0;
for ( my $run = 0 ; $run < $self->pings($target) ; $run++ ) {
- my ($t0,$t1,$t2,$t3); # Timestamps.
+ if (defined $t0) {
+ my $elapsed = tv_interval($t0, [gettimeofday]);
+ my $timeleft = $mininterval - $elapsed;
+ sleep $timeleft if $timeleft > 0;
+ }
+ my ($t1,$t2,$t3); # Timestamps.
#Temporary variables to play with.
my $ready;
@@ -184,7 +116,7 @@ sub pingone ($) {
close(Socket_Handle); next;
}
$nbytes = sysread( Socket_Handle, $buf, 1500 );
- if ($nbytes <= 0) {
+ if (not defined $nbytes or $nbytes <= 0) {
$self->do_debug("Read nothing and Connection closed!");
close(Socket_Handle); next;
}
@@ -222,7 +154,6 @@ sub pingone ($) {
}
- usleep($sleeptime);
}
@times =
map { sprintf "%.10e", $_ } sort { $a <=> $b } grep { $_ ne "-" } @times;
@@ -230,5 +161,78 @@ sub pingone ($) {
return @times;
}
+sub probevars {
+ my $class = shift;
+ my $h = $class->SUPER::probevars;
+ delete $h->{timeout};
+ return $h;
+}
+
+sub targetvars {
+ my $class = shift;
+ my $e = "=";
+ return $class->_makevars($class->SUPER::targetvars, {
+ greeting => {
+ _doc => <<DOC,
+Greeting string to send to the SSH Server. This will appear in the Logfile.
+Use this to make clear, who you are and what you are doing to avoid confusion.
+
+Also, don't use something that is a valid version string. This probe assumes
+that the connection gets terminated because of protocol mismatch.
+DOC
+ _default => "SSH-Latency-Measurement-Sorry-for-this-logmessage" ,
+ },
+ mininterval => {
+ _doc => "Minimum interval between the start of two connection attempts in (possibly fractional) seconds.",
+ _default => 0.5,
+ _re => '(\d*\.)?\d+',
+ },
+ interval => {
+ _doc => <<DOC,
+The interval to be measured. One of:
+
+${e}over
+
+${e}item connect
+
+Interval between connect() and the greeting string from the host.
+
+${e}item established
+
+Interval between our greeting message and the end of the connection
+because of Protocol mismatch. This is the default.
+
+${e}item complete
+
+From connect() to the end of the connection.
+
+${e}back
+
+DOC
+
+ _sub => sub {
+ my $interval = shift;
+ if(not ( $interval eq "connect"
+ or $interval eq "established"
+ or $interval eq "complete")) {
+ return "ERROR: Invalid interval parameter";
+ }
+ return undef;
+ },
+ _default => 'established',
+ },
+ timeout => {
+ _doc => 'Timeout for the connection.',
+ _re => '\d+',
+ _default => 5,
+ },
+ port => {
+ _doc => 'Connect to this port.',
+ _re => '\d+',
+ _default => 22,
+ },
+ });
+}
+
1;
diff --git a/lib/probes/CiscoRTTMonDNS.pm b/lib/probes/CiscoRTTMonDNS.pm
index 829a4de..691a39a 100644
--- a/lib/probes/CiscoRTTMonDNS.pm
+++ b/lib/probes/CiscoRTTMonDNS.pm
@@ -1,53 +1,51 @@
package probes::CiscoRTTMonDNS;
-# please use
-# pod2man CiscoRTTMonDNS.pm | nroff -man | more
-# to view the manpage of this document
-#
+=head1 301 Moved Permanently
+This is a Smokeping probe module. Please use the command
-=head1 NAME
+C<smokeping -man probes::CiscoRTTMonDNS>
-probes::CiscoRTTMonDNS.pm - Probe for SmokePing
-
-=head1 SYNOPSIS
-
- *** Probes ***
- + CiscoRTTMonDNS
- + forks=50
+to view the documentation or the command
- *** Targets ***
- + MyRouter-DNSserver
- menu = MyRouter->DNSserver
- title = RTTMon DNS lookup of www.foobar.com.au on DNSserver
- host = DNSserver.foobar.com.au
- probe=CiscoRTTMonDNS
- ++ PROBE_CONF
- ioshost = RTTcommunity@Myrouter.foobar.com.au
- name=www.foobar.com.au
- iosint = 10.33.22.11
+C<smokeping -makepod probes::CiscoRTTMonDNS>
-=head1 DESCRIPTION
+to generate the POD document.
-A probe for smokeping, which uses the ciscoRttMon MIB functionality ("Service Assurance Agent", "SAA") of Cisco IOS to time ( recursive, type A) DNS queries to a DNS server.
+=cut
-=head1 PARAMETERS
+use strict;
+use base qw(probes::basefork);
+use Symbol;
+use Carp;
+use BER;
+use SNMP_Session;
+use SNMP_util "0.97";
+use ciscoRttMonMIB "0.2";
-The (mandatory) host parameter specifies the DNS server, which the router will use. This can be a DNS name, the smokeping host can resolve or a dotted-quad IP address.
+my $e = "=";
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::CiscoRTTMonDNS.pm - Probe for SmokePing
+DOC,
+ description => <<DOC,
+A probe for smokeping, which uses the ciscoRttMon MIB functionality ("Service Assurance Agent", "SAA") of Cisco IOS to time ( recursive, type A) DNS queries to a DNS server.
-The (mandatory) ioshost parameter specifies the Cisco router, which will send the DNS requests, as well as the SNMP community string on the router.
+DOC
-The (mandatory) name parameter is the DNS name to resolve.
+ notes => <<DOC,
+${e}head2 host parameter
-The (optional) iosint parameter is the source address for the DNS packets. This should be one of the active (!) IP addresses of the router to get results. IOS looks up the target host address in the forwarding table and then uses the interface(s) listed there to send the DNS packets. By default IOS uses the (primary) IP address on the sending interface as source address for packets originated by the router.
+The host parameter specifies the DNS server, which the router will use.
-=head1 IOS VERSIONS
+${e}head2 IOS VERSIONS
This probe only works with IOS 12.0(3)T or higher. It is recommended to test it on less critical routers first.
-=head1 INSTALLATION
+${e}head2 INSTALLATION
-To install this probe copy ciscoRttMonMIB.pm to ($SMOKEPINGINSTALLDIR)/lib and CiscoRTTMonDNS.pm to ($SMOKEPINGINSTALLDIR)/lib/probes.
+To install this probe copy ciscoRttMonMIB.pm to (\$SMOKEPINGINSTALLDIR)/lib and CiscoRTTMonDNS.pm to (\$SMOKEPINGINSTALLDIR)/lib/probes.
The router(s) must be configured to allow read/write SNMP access. Sufficient is:
@@ -60,35 +58,24 @@ If you want to be a bit more restrictive with SNMP write access to the router, t
snmp-server community RTTCommunity view RttMon RW 2
The above configuration grants SNMP read-write only to 10.37.3.5 (the smokeping host) and only to the ciscoRttMon MIB tree. The probe does not need access to SNMP variables outside the RttMon tree.
-
-=head1 BUGS
-
+DOC
+ bugs => <<DOC,
The probe does unnecessary DNS queries, i.e. more than configured in the "pings" variable, because the RTTMon MIB only allows to set a total time for all queries in one measurement run (one "life"). Currently the probe sets the life duration to "pings"*2+3 seconds (2 secs is the timeout value hardcoded into this probe).
-
-=head1 SEE ALSO
-
+DOC
+ see_also => <<DOC,
http://people.ee.ethz.ch/~oetiker/webtools/smokeping/
+
http://www.switch.ch/misc/leinen/snmp/perl/
The best source for background info on SAA is Cisco's documentation on http://www.cisco.com and the CISCO-RTTMON-MIB documentation, which is available at:
-ftp://ftp.cisco.com/pub/mibs/v2/CISCO-RTTMON-MIB.my
-
-
-
-=head1 AUTHOR
+ftp://ftp.cisco.com/pub/mibs/v2/CISCO-RTTMON-MIB.my
+DOC
+ authors => <<DOC,
Joerg.Kummer at Roche.com
-
-=cut
-
-use strict;
-use base qw(probes::basefork);
-use Symbol;
-use Carp;
-use BER;
-use SNMP_Session;
-use SNMP_util "0.97";
-use ciscoRttMonMIB "0.2";
+DOC
+ }
+}
my $pingtimeout =2;
@@ -107,7 +94,6 @@ sub new($$$)
sub ProbeDesc($){
my $self = shift;
- my $bytes = $self->{properties}{packetsize} || 56;
return "CiscoRTTMonDNS.pm";
}
@@ -115,11 +101,6 @@ sub pingone ($$) {
my $self = shift;
my $target = shift;
- croak ("please define 'ioshost' under the PROBE_CONF section of your target\n")
- unless defined $target->{vars}{ioshost} ;
-
- croak ("please define 'name' under the PROBE_CONF section of your target\n")
- unless defined $target->{vars}{name} ;
my $name = $target->{vars}{name};
my $pings = $self->pings($target) || 20;
@@ -279,5 +260,35 @@ sub DestroyData ($$) {
&snmpset($host, "rttMonCtrlAdminStatus.$row", 'integer', 6);
}
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ _mandatory => [ 'ioshost', 'name' ],
+ ioshost => {
+ _doc => <<DOC,
+The (mandatory) ioshost parameter specifies the Cisco router, which will send the DNS requests,
+as well as the SNMP community string on the router.
+DOC
+ _example => 'RTTcommunity@Myrouter.foobar.com.au',
+ },
+ name => {
+ _doc => "The (mandatory) name parameter is the DNS name to resolve.",
+ _example => 'www.foobar.com.au',
+ },
+ iosint => {
+ _doc => <<DOC,
+The (optional) iosint parameter is the source address for the DNS packets.
+This should be one of the active (!) IP addresses of the router to get
+results. IOS looks up the target host address in the forwarding table
+and then uses the interface(s) listed there to send the DNS packets. By
+default IOS uses the (primary) IP address on the sending interface as
+source address for packets originated by the router.
+DOC
+ _example => '10.33.22.11',
+ },
+ });
+}
+
+=head1
1;
diff --git a/lib/probes/CiscoRTTMonEchoICMP.pm b/lib/probes/CiscoRTTMonEchoICMP.pm
index 9871813..c497ed9 100644
--- a/lib/probes/CiscoRTTMonEchoICMP.pm
+++ b/lib/probes/CiscoRTTMonEchoICMP.pm
@@ -1,49 +1,39 @@
package probes::CiscoRTTMonEchoICMP;
-# please use
-# pod2man CiscoRTTMonEchoICMP.pm | nroff -man | more
-# to view the manpage of this document
-#
+=head1 301 Moved Permanently
+This is a Smokeping probe module. Please use the command
-=head1 NAME
+C<smokeping -man probes::CiscoRTTMonEchoICMP>
-probes::CiscoRTTMonEchoICMP - Probe for SmokePing
+to view the documentation or the command
-=head1 SYNOPSIS
+C<smokeping -makepod probes::CiscoRTTMonEchoICMP>
- *** Probes ***
- + CiscoRTTMonEchoICMP
- + forks=50
+to generate the POD document.
- *** Targets ***
- + MyRouter-PingVictim
- menu = MyRouter->PingVictim
- title = RTTMon ping from MyRouter to PingVictim
- host = PingVictim.foobar.com.au
- ++ PROBE_CONF
- ioshost = RTTcommunity@Myrouter.foobar.com.au
- iosint = 10.33.22.11
- packetsize = 1024
- tos = 160
+=cut
-=head1 DESCRIPTION
+use strict;
+use base qw(probes::basefork);
+use Symbol;
+use Carp;
+use BER;
+use SNMP_Session;
+use SNMP_util "0.97";
+use ciscoRttMonMIB "0.2";
+sub pod_hash {
+ my $e = "=";
+ return {
+ name => <<DOC,
+probes::CiscoRTTMonEchoICMP - Probe for SmokePing
+DOC
+ description => <<DOC,
A probe for smokeping, which uses the ciscoRttMon MIB functionality ("Service Assurance Agent", "SAA") of Cisco IOS to measure ICMP echo ("ping") roundtrip times between a Cisco router and any IP address.
-
-=head1 PARAMETERS
-
-The (mandatory) host parameter specifies the IP host, which will be pinged by the router. This can be a DNS name, the smokeping host can resolve or a dotted-quad IP address.
-
-The (mandatory) ioshost parameter specifies the Cisco router, which will execute the pings, as well as the SNMP community string on the router.
-
-The (optional) packetsize parameter lets you configure the packetsize for the pings sent. The minimum is 8, the maximum 16392. Use the same number as with fping, if you want the same packet sizes being used on the network. Please note that the packesize must be specified under PROBE_CONF, all other definitions will be ignored. Default is 56 bytes.
-
-The (optional) iosint parameter is the source address for the pings sent. This should be one of the active (!) IP addresses of the router to get results. IOS looks up the target host address in the forwarding table and then uses the interface(s) listed there to send the ping packets. By default IOS uses the (primary) IP address on the sending interface as source address for a ping. The RTTMon MIB versions before IOS 12.0(3)T didn't support this parameter.
-
-The (optional) tos parameter specifies the value of the ToS byte in the IP header of the pings. Multiply DSCP values times 4 and Precedence values times 32 to calculate the ToS values to configure, e.g. ToS 160 corresponds to a DSCP value 40 and a Precedence value of 5. The RTTMon MIB versions before IOS 12.0(3)T didn't support this parameter.
-
-=head1 IOS VERSIONS
+DOC
+ notes => <<DOC,
+${e}head2 IOS VERSIONS
It is highly recommended to use this probe with routers running IOS 12.0(3)T or higher and to test it on less critical routers first. I managed to crash a router with 12.0(9) quite consistently ( in IOS lingo 12.0(9) is older code than 12.0(3)T ). I did not observe crashes on higher IOS releases, but messages on the router like the one below, when multiple processes concurrently accessed the same router (this case was IOS 12.1(12b) ):
@@ -52,9 +42,9 @@ Aug 20 07:30:14: %RTT-3-SemaphoreBadUnlock: %RTR: Attempt to unlock semaphore by
Aug 20 07:35:15: %RTT-3-SemaphoreInUse: %RTR: Could not obtain a lock for RTR. Process 80
-=head1 INSTALLATION
+${e}head2 INSTALLATION
-To install this probe copy ciscoRttMonMIB.pm files to ($SMOKEPINGINSTALLDIR)/lib and CiscoRTTMonEchoICMP.pm to ($SMOKEPINGINSTALLDIR)/lib/probes. V0.97 or higher of Simon Leinen's SNMP_Session.pm is required.
+To install this probe copy ciscoRttMonMIB.pm files to (\$SMOKEPINGINSTALLDIR)/lib and CiscoRTTMonEchoICMP.pm to (\$SMOKEPINGINSTALLDIR)/lib/probes. V0.97 or higher of Simon Leinen's SNMP_Session.pm is required.
The router(s) must be configured to allow read/write SNMP access. Sufficient is:
@@ -67,35 +57,23 @@ If you want to be a bit more restrictive with SNMP write access to the router, t
snmp-server community RTTCommunity view RttMon RW 2
The above configuration grants SNMP read-write only to 10.37.3.5 (the smokeping host) and only to the ciscoRttMon MIB tree. The probe does not need access to SNMP variables outside the RttMon tree.
-
-=head1 BUGS
-
+DOC
+ bugs => <<DOC,
The probe sends unnecessary pings, i.e. more than configured in the "pings" variable, because the RTTMon MIB only allows to set a total time for all pings in one measurement run (one "life"). Currently the probe sets the life duration to "pings"*2+3 seconds (2 secs is the ping timeout value hardcoded into this probe).
-
-=head1 SEE ALSO
-
+DOC
+ see_also => <<DOC,
http://people.ee.ethz.ch/~oetiker/webtools/smokeping/
+
http://www.switch.ch/misc/leinen/snmp/perl/
The best source for background info on SAA is Cisco's documentation on http://www.cisco.com and the CISCO-RTTMON-MIB documentation, which is available at:
ftp://ftp.cisco.com/pub/mibs/v2/CISCO-RTTMON-MIB.my
-
-
-
-=head1 AUTHOR
-
+DOC
+ authors => <<DOC,
Joerg.Kummer at Roche.com
-
-=cut
-
-use strict;
-use base qw(probes::basefork);
-use Symbol;
-use Carp;
-use BER;
-use SNMP_Session;
-use SNMP_util "0.97";
-use ciscoRttMonMIB "0.2";
+DOC
+ }
+}
my $pingtimeout =2;
@@ -114,7 +92,7 @@ sub new($$$)
sub ProbeDesc($){
my $self = shift;
- my $bytes = $self->{properties}{packetsize} || 56;
+ my $bytes = $self->{properties}{packetsize};
return "CiscoRTTMonEchoICMP ($bytes Bytes)";
}
@@ -122,12 +100,9 @@ sub pingone ($$) {
my $self = shift;
my $target = shift;
- croak ("please define 'ioshost' under the PROBE_CONF section of your target\n")
- unless defined $target->{vars}{ioshost} ;
-
my $pings = $self->pings($target) || 20;
- my $tos = $target->{vars}{tos} || 0;
- my $bytes = $target->{vars}{packetsize} || 56;
+ my $tos = $target->{vars}{tos};
+ my $bytes = $target->{properties}{packetsize};
# use the proces ID as as row number to make this poll distinct on the router;
my $row=$$;
@@ -285,5 +260,63 @@ sub DestroyData ($$) {
&snmpset($host, "rttMonCtrlAdminStatus.$row", 'integer', 6);
}
+sub probevars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::probevars, {
+ packetsize => {
+ _doc => <<DOC,
+The packetsize parameter lets you configure the packetsize for the pings
+sent. The minimum is 8, the maximum 16392. Use the same number as with
+fping, if you want the same packet sizes being used on the network.
+DOC
+ _default => 56,
+ _re => '\d+',
+ _sub => sub {
+ my $val = shift;
+ return "ERROR: packetsize must be between 8 and 16392"
+ unless $val >= 8 and $val <= 16392;
+ return undef;
+ },
+ },
+ });
+}
+
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ _mandatory => [ 'ioshost' ],
+ ioshost => {
+ _example => 'RTTcommunity@Myrouter.foobar.com.au',
+ _doc => <<DOC,
+The (mandatory) ioshost parameter specifies the Cisco router, which will
+execute the pings, as well as the SNMP community string on the router.
+DOC
+ },
+ iosint => {
+ _example => '10.33.22.11',
+ _doc => <<DOC,
+The (optional) iosint parameter is the source address for the pings
+sent. This should be one of the active (!) IP addresses of the router to
+get results. IOS looks up the target host address in the forwarding table
+and then uses the interface(s) listed there to send the ping packets. By
+default IOS uses the (primary) IP address on the sending interface as
+source address for a ping. The RTTMon MIB versions before IOS 12.0(3)T
+didn't support this parameter.
+DOC
+ },
+ tos => {
+ _example => 160,
+ _default => 0,
+ _doc => <<DOC,
+The (optional) tos parameter specifies the value of the ToS byte in
+the IP header of the pings. Multiply DSCP values times 4 and Precedence
+values times 32 to calculate the ToS values to configure, e.g. ToS 160
+corresponds to a DSCP value 40 and a Precedence value of 5. The RTTMon
+MIB versions before IOS 12.0(3)T didn't support this parameter.
+DOC
+ },
+ });
+}
+
1;
diff --git a/lib/probes/CiscoRTTMonTcpConnect.pm b/lib/probes/CiscoRTTMonTcpConnect.pm
index c0b07bf..84f2fe6 100644
--- a/lib/probes/CiscoRTTMonTcpConnect.pm
+++ b/lib/probes/CiscoRTTMonTcpConnect.pm
@@ -1,56 +1,45 @@
package probes::CiscoRTTMonTcpConnect;
-# please use
-# pod2man CiscoRTTMonTcpConnect.pm | nroff -man | more
-# to view the manpage of this document
-#
+=head1 301 Moved Permanently
+This is a Smokeping probe module. Please use the command
-=head1 NAME
+C<smokeping -man probes::CiscoRTTMonTcpConnect>
-probes::CiscoRTTMonTcpConnect - Probe for SmokePing
+to view the documentation or the command
-=head1 SYNOPSIS
+C<smokeping -makepod probes::CiscoRTTMonTcpConnect>
- *** Probes ***
- + CiscoRTTMonTcpConnect
- + forks=50
+to generate the POD document.
- *** Targets ***
- + MyRouter-TCPVictim
- menu = MyRouter->TCPVictim
- title = RTTMon TCP connect from MyRouter to TCPVictim
- host = TCPVictim.foobar.com.au
- probe=CiscoRTTMonTcpConnect
- ++ PROBE_CONF
- ioshost = RTTcommunity@Myrouter.foobar.com.au
- iosint = 10.33.22.11
- tos = 160
- port = 23
+=cut
-=head1 DESCRIPTION
+use strict;
+use base qw(probes::basefork);
+use Symbol;
+use Carp;
+use BER;
+use SNMP_Session;
+use SNMP_util "0.97";
+use ciscoRttMonMIB "0.2";
+sub pod_hash {
+ my $e = "=";
+ return {
+ name => <<DOC,
+probes::CiscoRTTMonTcpConnect - Probe for SmokePing
+DOC
+ description => <<DOC,
A probe for smokeping, which uses the ciscoRttMon MIB functionality ("Service Assurance Agent", "SAA") of Cisco IOS to measure TCP connect times between a Cisco router and a TCP server. The measured value is the time is the time to establish a TCP session, i.e. the time between the initial "SYN" TCP packet of the router and the "SYN ACK" packet of the host. The router terminates the TCP session immediately after the reception of "SYN ACK" with a "FIN" packet.
-
-=head1 PARAMETERS
-
-The (mandatory) host parameter specifies the IP host, which the router will connect to. This can be a DNS name, the smokeping host can resolve or a dotted-quad IP address.
-
-The (mandatory) ioshost parameter specifies the Cisco router, which will establish the TCP connections as well as the SNMP community string on the router.
-
-The (optional) port parameter lets you configure the destination TCP port on the host. The default is the http port 80.
-
-The (optional) iosint parameter is the source address for the TCP connections. This should be one of the active (!) IP addresses of the router to get results. IOS looks up the target host address in the forwarding table and then uses the interface(s) listed there to send the TCP packets. By default IOS uses the (primary) IP address on the sending interface as source address for a connection.
-
-The (optional) tos parameter specifies the value of the ToS byte in the IP header of the packets from the router. Multiply DSCP values times 4 and Precedence values times 32 to calculate the ToS values to configure, e.g. ToS 160 corresponds to a DSCP value 40 and a Precedence value of 5. Please note that this will not influence the ToS value in the packets sent by the the host.
-
-=head1 IOS VERSIONS
+DOC
+ notes => <<DOC,
+${e}head2 IOS VERSIONS
This probe only works with Cisco IOS 12.0(3)T or higher. It is recommended to test it on less critical routers first.
-=head1 INSTALLATION
+${e}head2 INSTALLATION
-To install this probe copy ciscoRttMonMIB.pm to ($SMOKEPINGINSTALLDIR)/lib and CiscoRTTMonTcpConnect.pm to ($SMOKEPINGINSTALLDIR)/lib/probes. V0.97 or higher of Simon Leinen's SNMP_Session.pm is required.
+To install this probe copy ciscoRttMonMIB.pm to (\$SMOKEPINGINSTALLDIR)/lib and CiscoRTTMonTcpConnect.pm to (\$SMOKEPINGINSTALLDIR)/lib/probes. V0.97 or higher of Simon Leinen's SNMP_Session.pm is required.
The router(s) must be configured to allow read/write SNMP access. Sufficient is:
@@ -63,35 +52,23 @@ If you want to be a bit more restrictive with SNMP write access to the router, t
snmp-server community RTTCommunity view RttMon RW 2
The above configuration grants SNMP read-write only to 10.37.3.5 (the smokeping host) and only to the ciscoRttMon MIB tree. The probe does not need access to SNMP variables outside the RttMon tree.
-
-=head1 BUGS
-
+DOC
+ bugs => <<DOC,
The probe establishes unnecessary connections, i.e. more than configured in the "pings" variable, because the RTTMon MIB only allows to set a total time for all connections in one measurement run (one "life"). Currently the probe sets the life duration to "pings"*2+3 seconds (2 secs is the timeout value hardcoded into this probe).
-
-=head1 SEE ALSO
-
+DOC
+ see_also => <<DOC,
http://people.ee.ethz.ch/~oetiker/webtools/smokeping/
+
http://www.switch.ch/misc/leinen/snmp/perl/
The best source for background info on SAA is Cisco's documentation on http://www.cisco.com and the CISCO-RTTMON-MIB documentation, which is available at:
ftp://ftp.cisco.com/pub/mibs/v2/CISCO-RTTMON-MIB.my
-
-
-
-=head1 AUTHOR
-
+DOC
+ authors => <<DOC,
Joerg.Kummer at Roche.com
-
-=cut
-
-use strict;
-use base qw(probes::basefork);
-use Symbol;
-use Carp;
-use BER;
-use SNMP_Session;
-use SNMP_util "0.97";
-use ciscoRttMonMIB "0.2";
+DOC
+ }
+}
my $pingtimeout =2;
@@ -110,20 +87,16 @@ sub new($$$)
sub ProbeDesc($){
my $self = shift;
- my $bytes = $self->{properties}{packetsize} || 56;
- return "CiscoRTTMonTcpConnect ($bytes Bytes)";
+ return "CiscoRTTMonTcpConnect";
}
sub pingone ($$) {
my $self = shift;
my $target = shift;
- croak ("please define 'ioshost' under the PROBE_CONF section of your target\n")
- unless defined $target->{vars}{ioshost} ;
-
my $pings = $self->pings($target) || 20;
- my $tos = $target->{vars}{tos} || 0;
- my $port = $target->{vars}{port} || 80;
+ my $tos = $target->{vars}{tos};
+ my $port = $target->{vars}{port};
# use the proces ID as as row number to make this poll distinct on the router;
my $row=$$;
@@ -281,5 +254,52 @@ sub DestroyData ($$) {
&snmpset($host, "rttMonCtrlAdminStatus.$row", 'integer', 6);
}
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ _mandatory => [ 'ioshost' ],
+ ioshost => {
+ _example => 'RTTcommunity@Myrouter.foobar.com.au',
+ _doc => <<DOC,
+The (mandatory) ioshost parameter specifies the Cisco router, which will
+establish the TCP connections as well as the SNMP community string on
+the router.
+DOC
+ },
+ port => {
+ _default => 80,
+ _re => '\d+',
+ _doc => <<DOC,
+The (optional) port parameter lets you configure the destination TCP
+port on the host. The default is the http port 80.
+DOC
+ },
+ iosint => {
+ _example => '10.33.22.11',
+ _doc => <<DOC,
+The (optional) iosint parameter is the source address for the TCP
+connections. This should be one of the active (!) IP addresses of the
+router to get results. IOS looks up the target host address in the
+forwarding table and then uses the interface(s) listed there to send
+the TCP packets. By default IOS uses the (primary) IP address on the
+sending interface as source address for a connection.
+DOC
+ },
+ tos => {
+ _default => 0,
+ _example => 160,
+ _re => '\d+',
+ _doc => <<DOC,
+The (optional) tos parameter specifies the value of the ToS byte in the
+IP header of the packets from the router. Multiply DSCP values times 4
+and Precedence values times 32 to calculate the ToS values to configure,
+e.g. ToS 160 corresponds to a DSCP value 40 and a Precedence value of
+5. Please note that this will not influence the ToS value in the packets
+sent by the the host.
+DOC
+ },
+ });
+}
+
1;
diff --git a/lib/probes/Curl.pm b/lib/probes/Curl.pm
index 9dc4d31..c7aaccb 100644
--- a/lib/probes/Curl.pm
+++ b/lib/probes/Curl.pm
@@ -1,105 +1,102 @@
package probes::Curl;
-my $DEFAULTBIN = "/usr/bin/curl";
-
-=head1 NAME
-
-probes::Curl - a curl(1) probe for SmokePing
-
-=head1 OVERVIEW
-
-Fetches an HTTP or HTTPS URL using curl(1).
-
-=head1 SYNOPSYS
-
- *** Probes ***
- + Curl
-
- binary = /usr/bin/curl # default value
-
- *** Targets ***
-
- probe = Curl
- forks = 10
-
- menu = Top
- title = Top Menu
- remark = Top Menu Remark
-
- + PROBE_CONF
+=head1 301 Moved Permanently
- + First
- menu = First
- title = First Target
- host = some.host
+This is a Smokeping probe module. Please use the command
- # PROBE_CONF can be overridden here
- ++ PROBE_CONF
- agent = "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2.1) Gecko/20021130"
- url = https://some.host/some/where
+C<smokeping -man probes::Curl>
-=head1 DESCRIPTION
+to view the documentation or the command
-Supported probe-specific variables:
+C<smokeping -makepod probes::Curl>
-=over
+to generate the POD document.
-=item binary
-
-The location of your curl binary.
-
-=item forks
-
-The number of concurrent processes to be run. See probes::basefork(3pm)
-for details.
-
-=item url
-
-The URL to fetch. Can be any one that curl supports.
+=cut
-=back
+use strict;
+use base qw(probes::basefork);
+use Carp;
-Supported target-level probe variables
-(see curl(1) for details of the options):
+my $DEFAULTBIN = "/usr/bin/curl";
-=over
+sub pod_hash {
+ return {
+ name => "probes::Curl - a curl(1) probe for SmokePing",
+ overview => "Fetches an HTTP or HTTPS URL using curl(1).",
+ description => "(see curl(1) for details of the options below)",
+ authors => <<'DOC',
+ Gerald Combs <gerald [AT] ethereal.com>
+ Niko Tyni <ntyni@iki.fi>
+DOC
+ notes => <<DOC,
+The URL to be tested used to be specified by the variable 'url' in earlier
+versions of Smokeping, and the 'host' setting did not influence it in any
+way. The variable name has now been changed to 'urlformat', and it can
+(and in most cases should) contain a placeholder for the 'host' variable.
+DOC
+ see_also => "curl(1), probes::Curl(3pm) etc., http://curl.haxx.se/",
+ }
+}
-=item agent
+sub probevars {
+ my $class = shift;
+ my $h = $class->SUPER::probevars;
+ delete $h->{timeout};
+ return $class->_makevars($h, {
+ binary => {
+ _doc => "The location of your curl binary.",
+ _default => $DEFAULTBIN,
+ _sub => sub {
+ my $val = shift;
+ return "ERROR: Curl 'binary' $val does not point to an executable"
+ unless -f $val and -x _;
+ return undef;
+ },
+ },
+ });
+}
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ _mandatory => [ 'urlformat' ],
+ agent => {
+ _doc => <<DOC,
The "-A" curl(1) option. This is a full HTTP User-Agent header including
the words "User-Agent:". It should be enclosed in quotes if it contains
-shell metacharacters
-
-=item ssl2
-
-The "-2" curl(1) option. Force SSL2.
-
-=item timeout
-
-The "-m" curl(1) option. Maximum timeout in seconds.
-
-=item interface
-
+shell metacharacters.
+DOC
+ _example => '"User-Agent: Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6c"',
+ },
+ timeout => {
+ _doc => qq{The "-m" curl(1) option. Maximum timeout in seconds.},
+ _re => '\d+',
+ _example => 10,
+ _default => 5,
+ },
+ interface => {
+ _doc => <<DOC,
The "--interface" curl(1) option. Bind to a specific interface, IP address or
host name.
+DOC
+ _example => 'eth0',
+ },
+ ssl2 => {
+ _doc => qq{The "-2" curl(1) option. Force SSL2.},
+ _example => 1,
+ },
+ urlformat => {
+ _doc => <<DOC,
+The template of the URL to fetch. Can be any one that curl supports.
+Any occurrence of the string '%host%' will be replaced with the
+host to be probed.
+DOC
+ _example => "http://%host%/",
+ },
+ });
+}
-=back
-
-=head1 AUTHORS
-
-Gerald Combs E<lt>gerald [AT] ethereal.comE<gt>
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
-
-=head1 SEE ALSO
-
-curl(1), probes::Curl(3pm) etc., http://curl.haxx.se/
-
-=cut
-
-use strict;
-use base qw(probes::basefork);
-use Carp;
-#
# derived class will mess with this through the 'features' method below
my $featurehash = {
agent => "-A",
@@ -121,12 +118,6 @@ sub new {
$self->_init if $self->can('_init');
- unless (defined $self->{properties}{binary}) {
- $self->{properties}{binary} = $DEFAULTBIN;
- }
- croak "ERROR: Curl 'binary' $self->{properties}{binary} does not point to an executable"
- unless -f $self->{properties}{binary} and -x $self->{properties}{binary};
-
$self->test_usage;
return $self;
@@ -156,15 +147,6 @@ sub ProbeDesc($) {
return "HTTP, HTTPS, and FTP URLs using curl(1)";
}
-# This can be overridden to tag the port number to the address
-# in derived classes (namely Curl)
-sub make_host {
- my $self = shift;
- my $target = shift;
- return $target->{addr};
-}
-
-
# other than host, count and protocol-specific args come from here
sub make_args {
my $self = shift;
@@ -174,7 +156,6 @@ sub make_args {
for (keys %arghash) {
my $val = $target->{vars}{$_};
- $val = $self->{properties}{$_} unless defined $val;
push @args, ($arghash{$_}, $val) if defined $val;
}
return @args;
@@ -199,8 +180,9 @@ sub make_commandline {
my $count = shift;
my @args = $self->make_args($target);
- my $url = $target->{vars}{url};
- $url = "" unless defined $url;
+ my $url = $target->{vars}{urlformat};
+ my $host = $target->{addr};
+ $url =~ s/%host%/$host/g;
push @args, $self->proto_args($target);
return ($self->{properties}{binary}, @args, $url);
diff --git a/lib/probes/DNS.pm b/lib/probes/DNS.pm
index 877ca97..1b4ec5c 100644
--- a/lib/probes/DNS.pm
+++ b/lib/probes/DNS.pm
@@ -1,78 +1,47 @@
package probes::DNS;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::DNS - Name Service Probe for SmokePing
+This is a Smokeping probe module. Please use the command
-=head1 SYNOPSIS
+C<smokeping -man probes::DNS>
- *** Probes ***
- + DNS
- binary = /usr/bin/dig
+to view the documentation or the command
- *** Targets ***
- probe = DNS
- forks = 10
+C<smokeping -makepod probes::DNS>
- + First
- menu = First
- title = First Target
- # ....
+to generate the POD document.
- ++ PROBE_CONF
- lookup=www.mozilla.org
+=cut
-=head1 DESCRIPTION
+use strict;
+use base qw(probes::basefork);
+use IPC::Open3;
+use Symbol;
+use Carp;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::DNS - Name Service Probe for SmokePing
+DOC
+ description => <<DOC,
Integrates dig as a probe into smokeping. The variable B<binary> must
point to your copy of the dig program. If it is not installed on
your system yet, you should install bind-utils >= 9.0.0.
The Probe asks the given host n-times for it's name. Where n is
the amount specified in the config File.
-
-Supported probe-specific variables:
-
-=over
-
-=item binary
-
-The location of your dig binary.
-
-=item forks
-
-The number of concurrent processes to be run. See probes::basefork(3pm)
-for details.
-
-=back
-
-Supported target-level probe variables:
-
-=over
-
-=item lookup
-
-Name of the host to look up in the dns.
-
-=back
-
-
-=head1 AUTHOR
-
-Igor Petrovski E<lt>pigor@myrealbox.comE<gt>,
-Carl Elkins E<lt>carl@celkins.org.ukE<gt>,
-Andre Stolze E<lt>stolze@uni-muenster.deE<gt>,
-Niko Tyni E<lt>ntyni@iki.fiE<gt>,
-Chris Poetzel<lt>cpoetzel@anl.gov<gt>
-
-
-=cut
-
-use strict;
-use base qw(probes::basefork);
-use IPC::Open3;
-use Symbol;
-use Carp;
+DOC
+ authors => <<'DOC',
+ Igor Petrovski <pigor@myrealbox.com>,
+ Carl Elkins <carl@celkins.org.uk>,
+ Andre Stolze <stolze@uni-muenster.de>,
+ Niko Tyni <ntyni@iki.fi>,
+ Chris Poetzel<cpoetzel@anl.gov>
+DOC
+ };
+}
my $dig_re=qr/query time:\s+([0-9.]+)\smsec.*/i;
@@ -85,11 +54,6 @@ sub new($$$)
# no need for this if we run as a cgi
unless ( $ENV{SERVER_SOFTWARE} ) {
- croak "ERROR: DNS 'binary' not defined in FPing probe definition"
- unless defined $self->{properties}{binary};
-
- croak "ERROR: DNS 'binary' does not point to an executable"
- unless -f $self->{properties}{binary} and -x $self->{properties}{binary};
my $call = "$self->{properties}{binary} localhost";
my $return = `$call 2>&1`;
if ($return =~ m/$dig_re/s){
@@ -103,6 +67,32 @@ sub new($$$)
return $self;
}
+sub probevars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::probevars, {
+ _mandatory => [ 'binary' ],
+ binary => {
+ _doc => "The location of your dig binary.",
+ _example => '/usr/bin/dig',
+ _sub => sub {
+ my $val = shift;
+ return "ERROR: DNS 'binary' does not point to an executable"
+ unless -f $val and -x _;
+ return undef;
+ },
+ },
+ });
+}
+
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ lookup => { _doc => "Name of the host to look up in the dns.",
+ _example => "www.example.org",
+ },
+ });
+}
+
sub ProbeDesc($){
my $self = shift;
return "DNS requests";
@@ -120,7 +110,6 @@ sub pingone ($){
my $lookuphost = $target->{vars}{lookup};
$lookuphost = $target->{addr} unless defined $lookuphost;
- #my $host = $target->{addr};
my $query = "$self->{properties}{binary} \@$host $lookuphost";
my @times;
diff --git a/lib/probes/EchoPing.pm b/lib/probes/EchoPing.pm
index d7558fa..843c9a1 100644
--- a/lib/probes/EchoPing.pm
+++ b/lib/probes/EchoPing.pm
@@ -1,134 +1,54 @@
package probes::EchoPing;
-my $DEFAULTBIN = "/usr/bin/echoping";
-
-=head1 NAME
-
-probes::EchoPing - an echoping(1) probe for SmokePing
-
-=head1 OVERVIEW
-
-Measures TCP or UDP echo (port 7) roundtrip times for SmokePing. Can also be
-used as a base class for other echoping(1) probes.
-
-=head1 SYNOPSYS
-
- *** Probes ***
- + EchoPing
-
- binary = /usr/bin/echoping # default value
-
- *** Targets ***
-
- probe = EchoPing
- forks = 10
-
- menu = Top
- title = Top Menu
- remark = Top Menu Remark
-
- + PROBE_CONF
-
- # none of these are mandatory
- timeout = 1
- waittime = 1
- udp = no
- size = 510
- tos = 0xa0
- priority = 6
-
- + First
- menu = First
- title = First Target
- host = router.example.com
-
- # PROBE_CONF can be overridden here
- ++ PROBE_CONF
- size = 300
-
-=head1 DESCRIPTION
-
-Supported probe-specific variables:
-
-=over
-
-=item binary
-
-The location of your echoping binary.
-
-=item forks
-
-The number of concurrent processes to be run. See probes::basefork(3pm)
-for details.
-
-=back
-
-Supported target-level probe variables
-(see echoping(1) for details of the options):
-
-=over
-
-=item timeout
-
-The "-t" echoping(1) option.
-
-=item waittime
-
-The "-w" echoping(1) option.
-
-=item size
-
-The "-s" echoping(1) option.
-
-=item udp
+=head1 301 Moved Permanently
-The "-u" echoping(1) option. Values other than '0' and 'no' enable UDP.
+This is a Smokeping probe module. Please use the command
-=item fill
+C<smokeping -man probes::EchoPing>
-The "-f" echoping(1) option.
+to view the documentation or the command
-=item priority
+C<smokeping -makepod probes::EchoPing>
-The "-p" echoping(1) option.
+to generate the POD document.
-=item tos
-
-The "-P" echoping(1) option.
-
-=item ipversion
-
-The IP protocol used. Possible values are "4" and "6".
-Passed to echoping(1) as the "-4" or "-6" options.
-
-=item extraopts
-
-Any extra options specified here will be passed unmodified to echoping(1).
+=cut
-=back
+use strict;
+use base qw(probes::basefork);
+use Carp;
-=head1 BUGS
+my $DEFAULTBIN = "/usr/bin/echoping";
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::EchoPing - an echoping(1) probe for SmokePing
+DOC
+ overview => <<DOC,
+Measures TCP or UDP echo (port 7) roundtrip times for SmokePing. Can also be
+used as a base class for other echoping(1) probes.
+DOC
+ description => <<DOC,
+See echoping(1) for details of the options below.
+DOC
+ bugs => <<DOC,
Should we test the availability of the service at startup? After that it's
too late to complain.
The location of the echoping binary should probably be a global variable
instead of a probe-specific one. As things are, every EchoPing -derived probe
-has to declare it if the default (/usr/bin/echoping) isn't correct.
-
-=head1 AUTHOR
-
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
-
-=head1 SEE ALSO
-
+has to declare it if the default ($DEFAULTBIN) isn't correct.
+DOC
+ authors => <<'DOC',
+Niko Tyni <ntyni@iki.fi>
+DOC
+ see_also => <<DOC,
echoping(1), probes::EchoPingHttp(3pm) etc., http://echoping.sourceforge.net/
+DOC
+ }
+}
-=cut
-
-use strict;
-use base qw(probes::basefork);
-use Carp;
#
# derived class will mess with this through the 'features' method below
my $featurehash = {
@@ -154,12 +74,6 @@ sub new {
$self->_init if $self->can('_init');
- unless (defined $self->{properties}{binary}) {
- $self->{properties}{binary} = $DEFAULTBIN;
- }
- croak "ERROR: EchoPing 'binary' $self->{properties}{binary} does not point to an executable"
- unless -f $self->{properties}{binary} and -x $self->{properties}{binary};
-
$self->test_usage;
return $self;
@@ -207,11 +121,9 @@ sub make_args {
for (keys %arghash) {
my $val = $target->{vars}{$_};
- $val = $self->{properties}{$_} unless defined $val;
push @args, ($arghash{$_}, $val) if defined $val;
}
push @args, $self->ipversion_arg($target);
- push @args, $self->{properties}{extraopts} if exists $self->{properties}{extraopts};
push @args, $target->{vars}{extraopts} if exists $target->{vars}{extraopts};
return @args;
@@ -240,7 +152,6 @@ sub udp_arg {
my @args;
my $udp = $target->{vars}{udp};
- $udp = $self->{properties}{udp} unless defined $udp;
push @args, "-u" if (defined $udp and $udp ne "no" and $udp ne "0");
return @args;
@@ -250,7 +161,6 @@ sub ipversion_arg {
my $self = shift;
my $target = shift;
my $vers = $target->{vars}{ipversion};
- $vers = $self->{properties}{ipversion} unless defined $vers;
if (defined $vers and $vers =~ /^([46])$/) {
return ("-" . $1);
} else {
@@ -295,9 +205,78 @@ sub pingone {
/^Elapsed time: (\d+\.\d+) seconds/ and push @times, $1;
}
close P;
- carp "WARNING: $cmd was not happy: $echoret\n" if $?;
+ $self->do_log("WARNING: $cmd was not happy: $echoret") if $?;
# carp("Got @times") if $self->debug;
return sort { $a <=> $b } @times;
}
+sub probevars {
+ my $class = shift;
+ my $h = $class->SUPER::probevars;
+ delete $h->{timeout};
+ return $class->_makevars($h, {
+ binary => {
+ _doc => "The location of your echoping binary.",
+ _default => $DEFAULTBIN,
+ _sub => sub {
+ my $val = shift;
+ -x $val or return "ERROR: binary '$val' is not executable";
+ return undef;
+ },
+ },
+ });
+}
+
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ timeout => {
+ _doc => 'The "-t" echoping(1) option.',
+ _example => 1,
+ _default => 5,
+ _re => '(\d*\.)?\d+',
+ },
+ waittime => {
+ _doc => 'The "-w" echoping(1) option.',
+ _example => 1,
+ _re => '\d+',
+ },
+ size => {
+ _doc => 'The "-s" echoping(1) option.',
+ _example => 510,
+ _re => '\d+',
+ },
+ udp => {
+ _doc => q{The "-u" echoping(1) option. Values other than '0' and 'no' enable UDP.},
+ _example => 'no',
+ },
+ fill => {
+ _doc => 'The "-f" echoping(1) option.',
+ _example => 'A',
+ _re => '.',
+ },
+ priority => {
+ _doc => 'The "-p" echoping(1) option.',
+ _example => 6,
+ _re => '\d+',
+ },
+ tos => {
+ _doc => 'The "-P" echoping(1) option.',
+ _example => '0xa0',
+ },
+ ipversion => {
+ _doc => <<DOC,
+The IP protocol used. Possible values are "4" and "6".
+Passed to echoping(1) as the "-4" or "-6" options.
+DOC
+ _example => 4,
+ _re => '[46]'
+ },
+ extraopts => {
+ _doc => 'Any extra options specified here will be passed unmodified to echoping(1).',
+ _example => '-some-letter-the-author-did-not-think-of',
+ },
+ });
+}
+
1;
diff --git a/lib/probes/EchoPingChargen.pm b/lib/probes/EchoPingChargen.pm
index 712953a..8f4cd9d 100644
--- a/lib/probes/EchoPingChargen.pm
+++ b/lib/probes/EchoPingChargen.pm
@@ -1,45 +1,43 @@
package probes::EchoPingChargen;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::EchoPingChargen - an echoping(1) probe for SmokePing
-
-=head1 OVERVIEW
-
-Measures TCP chargen (port 19) roundtrip times for SmokePing.
-
-=head1 SYNOPSYS
-
- *** Probes ***
- + EchoPingChargen
-
- binary = /usr/bin/echoping
-
- *** Targets ***
-
- probe = EchoPingChargen
-
-=head1 DESCRIPTION
-
-Supported probe- and target-specific variables: see probes::EchoPing(3pm)
+This is a Smokeping probe module. Please use the command
-Note: the I<udp> variable is not supported.
+C<smokeping -man probes::EchoPingChargen>
-=head1 AUTHOR
+to view the documentation or the command
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
+C<smokeping -makepod probes::EchoPingChargen>
-=head1 SEE ALSO
-
-probes::EchoPing(3pm)
+to generate the POD document.
=cut
-
use strict;
use base qw(probes::EchoPing);
use Carp;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::EchoPingChargen - an echoping(1) probe for SmokePing
+DOC
+ overview => <<DOC,
+Measures TCP chargen (port 19) roundtrip times for SmokePing.
+DOC
+ notes => <<DOC,
+The I<udp> variable is not supported.
+DOC
+ authors => <<'DOC',
+Niko Tyni <ntyni@iki.fi>
+DOC
+ see_also => <<DOC,
+probes::EchoPing(3pm)
+DOC
+ }
+}
+
sub proto_args {
return ("-c");
}
@@ -57,4 +55,11 @@ sub ProbeDesc($) {
return "TCP Chargen pings using echoping(1)";
}
+sub targetvars {
+ my $class = shift;
+ my $h = $class->SUPER::targetvars;
+ delete $h->{udp};
+ return $h;
+}
+
1;
diff --git a/lib/probes/EchoPingDiscard.pm b/lib/probes/EchoPingDiscard.pm
index e961090..7ee7c62 100644
--- a/lib/probes/EchoPingDiscard.pm
+++ b/lib/probes/EchoPingDiscard.pm
@@ -1,37 +1,35 @@
package probes::EchoPingDiscard;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::EchoPingDiscard - an echoping(1) probe for SmokePing
-
-=head1 OVERVIEW
-
-Measures TCP or UDP discard (port 9) roundtrip times for SmokePing.
-
-=head1 SYNOPSYS
-
- *** Probes ***
- + EchoPingDiscard
-
- binary = /usr/bin/echoping
-
- *** Targets ***
+This is a Smokeping probe module. Please use the command
- probe = EchoPingDiscard
+C<smokeping -man probes::EchoPingDiscard>
-=head1 DESCRIPTION
+to view the documentation or the command
-Supported probe- and target-specific variables: see probes::EchoPing(3pm)
+C<smokeping -makepod probes::EchoPingDiscard>
-=head1 AUTHOR
+to generate the POD document.
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
-
-=head1 SEE ALSO
+=cut
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::EchoPingDiscard - an echoping(1) probe for SmokePing
+DOC
+ overview => <<DOC,
+Measures TCP or UDP discard (port 9) roundtrip times for SmokePing.
+DOC
+ authors => <<'DOC',
+Niko Tyni <ntyni@iki.fi>
+DOC
+ see_also => <<DOC,
probes::EchoPing(3pm)
-
-=cut
+DOC
+ }
+}
use strict;
use base qw(probes::EchoPing);
diff --git a/lib/probes/EchoPingHttp.pm b/lib/probes/EchoPingHttp.pm
index 4e261b8..e2fe1c0 100644
--- a/lib/probes/EchoPingHttp.pm
+++ b/lib/probes/EchoPingHttp.pm
@@ -1,79 +1,16 @@
package probes::EchoPingHttp;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::EchoPingHttp - an echoping(1) probe for SmokePing
-
-=head1 OVERVIEW
-
-Measures HTTP roundtrip times (web servers and caches) for SmokePing.
-
-=head1 SYNOPSYS
-
- *** Probes ***
- + EchoPingHttp
-
- binary = /usr/bin/echoping # mandatory
-
-
- *** Targets ***
-
- probe = EchoPingHttp
-
- + PROBE_CONF
- url = /
- ignore_cache = yes
- revalidate_data = no
- port = 80 # default value anyway
- timeout = 50 # default is 10s
-
-=head1 DESCRIPTION
-
-Supported probe-specific variables: those specified in EchoPing(3pm)
-documentation.
-
-Supported target-specific variables:
-
-=over
-
-=item those specified in EchoPing(3pm) documentation
-
-except I<fill>, I<size> and I<udp>.
-
-=item url
-
-The URL to be requested from the web server or cache. Can be either relative
-(/...) for web servers or absolute (http://...) for caches.
-
-=item port
-
-The TCP port to use. The default is 80.
-
-=item ignore_cache
-
-The echoping(1) "-A" option: force the proxy to ignore the cache.
-Enabled if the value is anything other than 'no' or '0'.
-
-=item revalidate_data
-
-The echoping(1) "-a" option: force the proxy to revalidate data with original
-server. Enabled if the value is anything other than 'no' or '0'.
+This is a Smokeping probe module. Please use the command
-=item timeout
+C<smokeping -man probes::EchoPingHttp>
-The echoping(1) "-t" option: Number of seconds to wait a reply before giving up. For TCP,
-this is the maximum number of seconds for the whole connection
-(setup and data exchange).
+to view the documentation or the command
-=back
+C<smokeping -makepod probes::EchoPingHttp>
-=head1 AUTHOR
-
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
-
-=head1 SEE ALSO
-
-EchoPing(3pm), EchoPingHttps(3pm)
+to generate the POD document.
=cut
@@ -81,6 +18,26 @@ use strict;
use base qw(probes::EchoPing);
use Carp;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::EchoPingHttp - an echoping(1) probe for SmokePing
+DOC
+ overview => <<DOC,
+Measures HTTP roundtrip times (web servers and caches) for SmokePing.
+DOC
+ notes => <<DOC,
+The I<fill>, I<size> and I<udp> EchoPing variables are not valid for EchoPingHttp.
+DOC
+ authors => <<'DOC',
+Niko Tyni <ntyni@iki.fi>
+DOC
+ see_also => <<DOC,
+EchoPing(3pm), EchoPingHttps(3pm)
+DOC
+ }
+}
+
sub _init {
my $self = shift;
# HTTP doesn't fit with filling or size
@@ -96,7 +53,6 @@ sub make_host {
my $host = $self->SUPER::make_host($target);
my $port = $target->{vars}{port};
- $port = $self->{properties}{port} unless defined $port;
$host .= ":$port" if defined $port;
return $host;
@@ -106,21 +62,11 @@ sub proto_args {
my $self = shift;
my $target = shift;
my $url = $target->{vars}{url};
- $url = $self->{properties}{url} unless defined $url;
- $url = "/" unless defined $url;
my @args = ("-h", $url);
- # -t : timeout
- my $timeout = $target->{vars}{timeout};
- $timeout = $self->{properties}{timeout}
- unless defined $timeout;
- push @args, "-t $timeout" if $timeout;
-
# -A : ignore cache
my $ignore = $target->{vars}{ignore_cache};
- $ignore = $self->{properties}{ignore_cache}
- unless defined $ignore;
$ignore = 1
if (defined $ignore and $ignore ne "no"
and $ignore ne "0");
@@ -128,8 +74,6 @@ sub proto_args {
# -a : force cache to revalidate the data
my $revalidate = $target->{vars}{revalidate_data};
- $revalidate = $self->{properties}{revalidate_data}
- unless defined $revalidate;
$revalidate= 1 if (defined $revalidate and $revalidate ne "no"
and $revalidate ne "0");
push @args, "-a" if $revalidate and not exists $self->{_disabled}{a};
@@ -160,5 +104,40 @@ sub ProbeDesc($) {
return "HTTP pings using echoping(1)";
}
+sub targetvars {
+ my $class = shift;
+ my $h = $class->SUPER::targetvars;
+ delete $h->{udp};
+ delete $h->{fill};
+ delete $h->{size};
+ return $class->_makevars($h, {
+ url => {
+ _doc => <<DOC,
+The URL to be requested from the web server or cache. Can be either relative
+(/...) for web servers or absolute (http://...) for caches.
+DOC
+ _default => '/',
+ },
+ port => {
+ _doc => 'The TCP port to use.',
+ _example => 80,
+ _re => '\d+',
+ },
+ ignore_cache => {
+ _doc => <<DOC,
+The echoping(1) "-A" option: force the proxy to ignore the cache.
+Enabled if the value is anything other than 'no' or '0'.
+DOC
+ _example => 'yes',
+ },
+ revalidate_data => {
+ _doc => <<DOC,
+The echoping(1) "-a" option: force the proxy to revalidate data with original
+server. Enabled if the value is anything other than 'no' or '0'.
+DOC
+ _example => 'no',
+ },
+ });
+}
1;
diff --git a/lib/probes/EchoPingHttps.pm b/lib/probes/EchoPingHttps.pm
index 84f8b85..c860559 100644
--- a/lib/probes/EchoPingHttps.pm
+++ b/lib/probes/EchoPingHttps.pm
@@ -1,42 +1,16 @@
package probes::EchoPingHttps;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::EchoPingHttps - an echoping(1) probe for SmokePing
-
-=head1 OVERVIEW
-
-Measures HTTPS (HTTP over SSL) roundtrip times (web servers and caches) for
-SmokePing.
-
-=head1 SYNOPSYS
-
- *** Probes ***
- + EchoPingHttps
-
- binary = /usr/bin/echoping # mandatory
-
- *** Targets ***
-
- probe = EchoPingHttps
-
- + PROBE_CONF
- url = /
- ignore-cache = yes
- force-revalidate = no
- port = 443 # default value anyway
+This is a Smokeping probe module. Please use the command
-=head1 DESCRIPTION
+C<smokeping -man probes::EchoPingHttps>
-As EchoPingHttp(3pm), but SSL-enabled.
-
-=head1 AUTHOR
-
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
+to view the documentation or the command
-=head1 SEE ALSO
+C<smokeping -makepod probes::EchoPingHttps>
-EchoPingHttp(3pm)
+to generate the POD document.
=cut
@@ -44,6 +18,27 @@ use strict;
use base qw(probes::EchoPingHttp);
use Carp;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::EchoPingHttps - an echoping(1) probe for SmokePing
+DOC
+ overview => <<DOC,
+Measures HTTPS (HTTP over SSL) roundtrip times (web servers and caches) for
+SmokePing.
+DOC
+ description => <<DOC,
+As EchoPingHttp(3pm), but SSL-enabled.
+DOC
+ authors => <<'DOC',
+Niko Tyni <ntyni@iki.fi>
+DOC
+ see_also => <<DOC,
+EchoPingHttp(3pm)
+DOC
+ }
+}
+
sub proto_args {
my $self = shift;
my $target = shift;
diff --git a/lib/probes/EchoPingIcp.pm b/lib/probes/EchoPingIcp.pm
index 13ba896..dc93fab 100644
--- a/lib/probes/EchoPingIcp.pm
+++ b/lib/probes/EchoPingIcp.pm
@@ -1,56 +1,16 @@
package probes::EchoPingIcp;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::EchoPingIcp - an echoping(1) probe for SmokePing
-
-=head1 OVERVIEW
-
-Measures ICP (Internet Cache Protocol, spoken by web caches)
-roundtrip times for SmokePing.
-
-=head1 SYNOPSYS
-
- *** Probes ***
- + EchoPingIcp
-
- binary = /usr/bin/echoping # mandatory
-
- *** Targets ***
-
- probe = EchoPingHttp
-
- + PROBE_CONF
- # this can be overridden in the targets' PROBE_CONF sections
- url = /
-
-
-=head1 DESCRIPTION
-
-Supported probe-specific variables: those specified in EchoPing(3pm)
-documentation.
-
-Supported target-specific variables:
-
-=over
+This is a Smokeping probe module. Please use the command
-=item those specified in EchoPing(3pm) documentation
+C<smokeping -man probes::EchoPingIcp>
-except I<fill>, I<size> and I<udp>.
+to view the documentation or the command
-=item url
+C<smokeping -makepod probes::EchoPingIcp>
-The URL to be requested from the web cache.
-
-=back
-
-=head1 AUTHOR
-
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
-
-=head1 SEE ALSO
-
-EchoPing(3pm), EchoPingHttp(3pm)
+to generate the POD document.
=cut
@@ -58,6 +18,27 @@ use strict;
use base qw(probes::EchoPing);
use Carp;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::EchoPingIcp - an echoping(1) probe for SmokePing
+DOC
+ overview => <<DOC,
+Measures ICP (Internet Cache Protocol, spoken by web caches)
+roundtrip times for SmokePing.
+DOC
+ notes => <<DOC,
+The I<fill>, I<size> and I<udp> EchoPing variables are not valid.
+DOC
+ authors => <<'DOC',
+Niko Tyni <ntyni@iki.fi>
+DOC
+ see_also => <<DOC,
+EchoPing(3pm), EchoPingHttp(3pm)
+DOC
+ }
+}
+
sub _init {
my $self = shift;
# Icp doesn't fit with filling or size
@@ -70,8 +51,6 @@ sub proto_args {
my $self = shift;
my $target = shift;
my $url = $target->{vars}{url};
- $url = $self->{properties}{url} unless defined $url;
- $url = "/" unless defined $url;
my @args = ("-i", $url);
@@ -82,7 +61,7 @@ sub test_usage {
my $self = shift;
my $bin = $self->{properties}{binary};
croak("Your echoping binary doesn't support ICP")
- if `$bin -i/ 127.0.0.1 2>&1` =~ /not compiled|usage/i;
+ if `$bin -t1 -i/ 127.0.0.1 2>&1` =~ /not compiled|usage/i;
$self->SUPER::test_usage;
return;
}
@@ -91,4 +70,19 @@ sub ProbeDesc($) {
return "ICP pings using echoping(1)";
}
+sub targetvars {
+ my $class = shift;
+ my $h = $class->SUPER::targetvars;
+ delete $h->{udp};
+ delete $h->{fill};
+ delete $h->{size};
+ return $class->_makevars($h, {
+ _mandatory => [ 'url' ],
+ url => {
+ _doc => "The URL to be requested from the web cache.",
+ _example => 'http://www.example.org/',
+ },
+ });
+}
+
1;
diff --git a/lib/probes/EchoPingSmtp.pm b/lib/probes/EchoPingSmtp.pm
index ef6eba0..0518758 100644
--- a/lib/probes/EchoPingSmtp.pm
+++ b/lib/probes/EchoPingSmtp.pm
@@ -1,38 +1,16 @@
package probes::EchoPingSmtp;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::EchoPingSmtp - an echoping(1) probe for SmokePing
-
-=head1 OVERVIEW
-
-Measures SMTP roundtrip times (mail servers) for SmokePing.
-
-=head1 SYNOPSYS
-
- *** Probes ***
- + EchoPingSmtp
-
- binary = /usr/bin/echoping # mandatory
-
- *** Targets ***
- probe = EchoPingSmtp
-
-=head1 DESCRIPTION
-
-Supported probe-specific variables: those specified in EchoPing(3pm)
-documentation.
+This is a Smokeping probe module. Please use the command
-Supported target-specific variables: those specified in
-EchoPing(3pm) documentation except I<fill>, I<size> and I<udp>.
+C<smokeping -man probes::EchoPingSmtp>
-=head1 AUTHOR
+to view the documentation or the command
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
+C<smokeping -makepod probes::EchoPingSmtp>
-=head1 SEE ALSO
-
-EchoPing(3pm)
+to generate the POD document.
=cut
@@ -40,6 +18,26 @@ use strict;
use base qw(probes::EchoPing);
use Carp;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::EchoPingSmtp - an echoping(1) probe for SmokePing
+DOC
+ overview => <<DOC,
+Measures SMTP roundtrip times (mail servers) for SmokePing.
+DOC
+ notes => <<DOC,
+The I<fill>, I<size> and I<udp> EchoPing variables are not valid.
+DOC
+ authors => <<'DOC',
+Niko Tyni <ntyni@iki.fi>
+DOC
+ see_also => <<DOC,
+EchoPing(3pm)
+DOC
+ }
+}
+
sub _init {
my $self = shift;
# SMTP doesn't fit with filling or size
@@ -65,4 +63,13 @@ sub ProbeDesc($) {
return "SMTP pings using echoping(1)";
}
+sub targetvars {
+ my $class = shift;
+ my $h = $class->SUPER::targetvars;
+ delete $h->{udp};
+ delete $h->{fill};
+ delete $h->{size};
+ return $h;
+}
+
1;
diff --git a/lib/probes/FPing.pm b/lib/probes/FPing.pm
index 9e146f6..5f92138 100644
--- a/lib/probes/FPing.pm
+++ b/lib/probes/FPing.pm
@@ -1,23 +1,37 @@
package probes::FPing;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::FPing - FPing Probe for SmokePing
+This is a Smokeping probe module. Please use the command
+
+C<smokeping -man probes::FPing>
-=head1 SYNOPSIS
+to view the documentation or the command
- *** Probes ***
- + FPing
- binary = /usr/sepp/bin/fping
- packetsize = 1024
+C<smokeping -makepod probes::FPing>
-=head1 DESCRIPTION
+to generate the POD document.
+
+=cut
-Integrates FPing as a probe into smokeping. The variable B<binary> must
-point to your copy of the FPing program. If it is not installed on
+use strict;
+use base qw(probes::base);
+use IPC::Open3;
+use Symbol;
+use Carp;
+
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::FPing - FPing Probe for SmokePing
+DOC
+ description => <<DOC,
+Integrates FPing as a probe into smokeping. The variable B<binary> must
+point to your copy of the FPing program. If it is not installed on
your system yet, you can get it from http://www.fping.com/.
+
+The (optional) B<packetsize> option lets you configure the packetsize for the pings sent.
-The (optional) packetsize option lets you configure the packetsize for the pings sent.
The FPing manpage has the following to say on this topic:
Number of bytes of ping data to send. The minimum size (normally 12) allows
@@ -27,18 +41,12 @@ timestamp). The reported received data size includes the IP header
40 bytes. Default is 56, as in ping. Maximum is the theoretical maximum IP
datagram size (64K), though most systems limit this to a smaller,
system-dependent number.
-
-=head1 AUTHOR
-
+DOC
+ authors => <<'DOC',
Tobias Oetiker <tobi@oetiker.ch>
-
-=cut
-
-use strict;
-use base qw(probes::base);
-use IPC::Open3;
-use Symbol;
-use Carp;
+DOC
+ }
+}
sub new($$$)
{
@@ -48,17 +56,11 @@ sub new($$$)
# no need for this if we run as a cgi
unless ( $ENV{SERVER_SOFTWARE} ) {
- croak "ERROR: FPing packetsize must be between 12 and 64000"
- if $self->{properties}{packetsize} and
- ( $self->{properties}{packetsize} < 12 or $self->{properties}{packetsize} > 64000 );
-
- croak "ERROR: FPing 'binary' not defined in FPing probe definition"
- unless defined $self->{properties}{binary};
-
- croak "ERROR: FPing 'binary' does not point to an executable"
- unless -f $self->{properties}{binary} and -x $self->{properties}{binary};
-
- my $return = `$self->{properties}{binary} -C 1 localhost 2>&1`;
+ my $binary = join(" ", $self->binary);
+ my $testhost = $self->testhost;
+ my $return = `$binary -C 1 $testhost 2>&1`;
+ croak "ERROR: fping ('$binary -C 1 $testhost') could not be run: $return"
+ if $return =~ m/not found/;
croak "ERROR: FPing must be installed setuid root or it will not work\n"
if $return =~ m/only.+root/;
@@ -76,10 +78,21 @@ sub new($$$)
sub ProbeDesc($){
my $self = shift;
- my $bytes = $self->{properties}{packetsize} || 56;
+ my $bytes = $self->{properties}{packetsize}||56;
return "ICMP Echo Pings ($bytes Bytes)";
}
+# derived class (ie. RemoteFPing) can override this
+sub binary {
+ my $self = shift;
+ return $self->{properties}{binary};
+}
+
+# derived class (ie. FPing6) can override this
+sub testhost {
+ return "localhost";
+}
+
sub ping ($){
my $self = shift;
# do NOT call superclass ... the ping method MUST be overwriten
@@ -91,9 +104,13 @@ sub ping ($){
return unless @{$self->addresses};
my @bytes = () ;
push @bytes, "-b$self->{properties}{packetsize}" if $self->{properties}{packetsize};
+ my @timeout = ();
+ push @timeout, "-t" . int(1000 * $self->{properties}{timeout}) if $self->{properties}{timeout};
my @cmd = (
- $self->{properties}{binary}, @bytes,
- '-C', $self->pings, '-q','-B1','-i10','-r1',
+ $self->binary, @bytes,
+ '-C', $self->pings, '-q','-B1','-r1',
+ '-i' . $self->{properties}{mindelay},
+ @timeout,
@{$self->addresses});
$self->do_debug("Executing @cmd");
my $pid = open3($inh,$outh,$errh, @cmd);
@@ -114,4 +131,54 @@ sub ping ($){
close $errh;
}
+sub probevars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::probevars, {
+ _mandatory => [ 'binary' ],
+ binary => {
+ _sub => sub {
+ my ($val) = @_;
+ return "ERROR: FPing 'binary' does not point to an executable"
+ unless -f $val and -x _;
+ return undef;
+ },
+ _doc => "The location of your fping binary.",
+ _example => '/usr/bin/fping',
+ },
+ packetsize => {
+ _re => '\d+',
+ _example => 5000,
+ _sub => sub {
+ my ($val) = @_;
+ return "ERROR: FPing packetsize must be between 12 and 64000"
+ if ( $val < 12 or $val > 64000 );
+ return undef;
+ },
+ _doc => "The ping packet size (in the range of 12-64000 bytes).",
+
+ },
+ timeout => {
+ _re => '(\d*\.)?\d+',
+ _example => 1.5,
+ _doc => <<DOC,
+The fping "-t" parameter, but in (possibly fractional) seconds rather than
+milliseconds, for consistency with other Smokeping probes. From fping(1):
+
+Initial target timeout. In the default mode, this is the amount of time that
+ping waits for a response to its first request. Successive timeouts are multiplied by the backoff factor.
+DOC
+ },
+ mindelay => {
+ _re => '(\d*\.)?\d+',
+ _example => 1,
+ _default => 10,
+ _doc => <<DOC,
+The fping "-i" parameter. From fping(1):
+
+The minimum amount of time (in milliseconds) between sending a ping packet to any target.
+DOC
+ },
+ });
+}
+
1;
diff --git a/lib/probes/FPing.pm.orig b/lib/probes/FPing.pm.orig
deleted file mode 100644
index e71ceb0..0000000
--- a/lib/probes/FPing.pm.orig
+++ /dev/null
@@ -1,115 +0,0 @@
-package probes::FPing;
-
-=head1 NAME
-
-probes::FPing - FPing Probe for SmokePing
-
-=head1 SYNOPSIS
-
- *** Probes ***
- + FPing
- binary = /usr/sepp/bin/fping
- packetsize = 1024
-
-=head1 DESCRIPTION
-
-Integrates FPing as a probe into smokeping. The variable B<binary> must
-point to your copy of the FPing program. If it is not installed on
-your system yet, you can get it from http://www.fping.com/.
-
-The (optional) packetsize option lets you configure the packetsize for the pings sent.
-The FPing manpage has the following to say on this toppic:
-
-Number of bytes of ping data to send. The minimum size (normally 12) allows
-room for the data that fping needs to do its work (sequence number,
-timestamp). The reported received data size includes the IP header
-(normally 20 bytes) and ICMP header (8 bytes), so the minimum total size is
-40 bytes. Default is 56, as in ping. Maximum is the theoretical maximum IP
-datagram size (64K), though most systems limit this to a smaller,
-system-dependent number.
-
-=head1 AUTHOR
-
-Tobias Oetiker <tobi@oetiker.ch>
-
-=cut
-
-use strict;
-use base qw(probes::base);
-use IPC::Open3;
-use Symbol;
-use Carp;
-
-sub new($$$)
-{
- my $proto = shift;
- my $class = ref($proto) || $proto;
- my $self = $class->SUPER::new(@_);
-
- # no need for this if we run as a cgi
- unless ( $ENV{SERVER_SOFTWARE} ) {
- croak "ERROR: FPing packetsize must be between 12 and 64000"
- if $self->{properties}{packetsize} and
- ( $self->{properties}{packetsize} < 12 or $self->{properties}{packetsize} > 64000 );
-
- croak "ERROR: FPing 'binary' not defined in FPing probe definition"
- unless defined $self->{properties}{binary};
-
- croak "ERROR: FPing 'binary' does not point to an executable"
- unless -f $self->{properties}{binary} and -x $self->{properties}{binary};
-
- my $return = `$self->{properties}{binary} -C 1 localhost 2>&1`;
- croak "ERROR: FPing must be installed setuid root or it will not work\n"
- if $return =~ m/only.+root/;
-
- if ($return =~ m/bytes, ([0-9.]+)\sms\s+.*\n.*\n.*:\s+([0-9.]+)/){
- $self->{pingfactor} = 1000 * $2/$1;
- print "### fping seems to report in ", $1/$2, " miliseconds\n";
- } else {
- $self->{pingfactor} = 1000; # Gives us a good-guess default
- print "### assuming you are using an fping copy reporting in miliseconds\n";
- }
- };
-
- return $self;
-}
-
-sub ProbeDesc($){
- my $self = shift;
- my $bytes = $self->{properties}{packetsize} || 56;
- return "ICMP Echo Pings ($bytes Bytes)";
-}
-
-sub ping ($){
- my $self = shift;
- # do NOT call superclass ... the ping method MUST be overwriten
- my %upd;
- my $inh = gensym;
- my $outh = gensym;
- my $errh = gensym;
- # pinging nothing is pointless
- return unless @{$self->addresses};
- my @bytes = () ;
- push @bytes, "-b$self->{properties}{packetsize}" if $self->{properties}{packetsize};
- my $pid = open3($inh,$outh,$errh,
- $self->{properties}{binary}, @bytes,
- '-C', $self->{cfg}{Database}{pings}, '-q','-B1','-i10','-r1',
- @{$self->addresses});
- $self->{rtts}={};
- while (<$errh>){
- chomp;
- next unless /^\S+\s+:\s+[\d\.]/; #filter out error messages from fping
- my @times = split /\s+/;
- my $ip = shift @times;
- next unless ':' eq shift @times; #drop the colon
-
- @times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} grep /^\d/, @times;
- map { $self->{rtts}{$_} = [@times] } @{$self->{addrlookup}{$ip}} ;
- }
- waitpid $pid,0;
- close $inh;
- close $outh;
- close $errh;
-}
-
-1;
diff --git a/lib/probes/FPing6.pm b/lib/probes/FPing6.pm
index 7a03b48..e35e2e1 100644
--- a/lib/probes/FPing6.pm
+++ b/lib/probes/FPing6.pm
@@ -1,91 +1,52 @@
package probes::FPing6;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::FPing6 - FPing6 Probe for SmokePing
-
-=head1 SYNOPSIS
+This is a Smokeping probe module. Please use the command
- *** Probes ***
- + FPing6
- binary = /usr/sbin/fping6
+C<smokeping -man probes::FPing6>
-=head1 DESCRIPTION
+to view the documentation or the command
-Integrates FPing6 as a probe into smokeping. The variable B<binary> must
-point to your copy of the FPing6 program. If it is not installed on
-your system yet, you can get it from http://www.fping.com/.
+C<smokeping -makepod probes::FPing6>
-=head1 AUTHOR
-
-Tobias Oetiker <tobi@oetiker.ch>
+to generate the POD document.
=cut
use strict;
-use base qw(probes::base);
-use IPC::Open3;
-use Symbol;
-use Carp;
-
-sub new($$$)
-{
- my $proto = shift;
- my $class = ref($proto) || $proto;
- my $self = $class->SUPER::new(@_);
+use base qw(probes::FPing);
- croak "ERROR: FPing6 'binary' not defined in FPing6 probe definition"
- unless defined $self->{properties}{binary};
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::FPing6 - FPing6 Probe for SmokePing
+DOC
+ description => <<DOC,
+Integrates FPing6 as a probe into smokeping. This probe is derived from
+FPing; the only difference is that the target host used for checking
+the fping command output is ::1 instead of localhost.
+DOC
+ authors => <<'DOC',
+Tobias Oetiker <tobi@oetiker.ch>
- croak "ERROR: FPing6 'binary' does not point to an executable"
- unless -f $self->{properties}{binary} and -x $self->{properties}{binary};
-
- $_ = `$self->{properties}{binary} -C 1 localhost 2>&1`;
- croak "ERROR: FPing6 must be installed setuid root or it will not work\n" if m/only.+root/;
- if (m/bytes, ([0-9.]+)\sms\s+.*\n.*\n.*:\s+([0-9.]+)/){
- $self->{pingfactor} = 1000 * $2/$1;
- print "### fping6 seems to report in ", $1/$2, " miliseconds\n" unless $ENV{SERVER_SOFTWARE};
- } else {
- $self->{pingfactor} = 1000; # Gives us a good-guess default
- print "### assuming you are using an fping6 copy reporting in miliseconds\n" unless $ENV{SERVER_SOFTWARE};
- };
- return $self;
+Niko Tyni <ntyni@iki.fi>
+DOC
+ see_also => <<DOC
+probes::FPing
+DOC
+ }
}
-sub ProbeDesc($){
- return "IPv6-ICMP Echo Pings";
+sub testhost {
+ return "::1";
}
-sub ping ($){
- my $self = shift;
- # do NOT call superclass ... the ping method MUST be overwriten
- my %upd;
- my $inh = gensym;
- my $outh = gensym;
- my $errh = gensym;
- # pinging nothing is pointless
- return unless @{$self->addresses};
- my @cmd = (
- $self->{properties}{binary},
- '-C', $self->pings, '-q',
- @{$self->addresses});
- $self->do_debug("Executing @cmd");
- my $pid = open3($inh,$outh,$errh, @cmd);
- $self->{rtts}={};
- while (<$errh>){
- chomp;
- next unless /^\S+\s+:\s+[\d\.]/; #filter out error messages from fping
- my @times = split /\s+/;
- my $ip = shift @times;
- next unless ':' eq shift @times; #drop the colon
-
- @times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} grep {$_ ne "-"} @times;
- map { $self->{rtts}{$_} = [@times] } @{$self->{addrlookup}{$ip}} ;
- }
- waitpid $pid,0;
- close $inh;
- close $outh;
- close $errh;
+sub probevars {
+ my $self = shift;
+ my $h = $self->SUPER::probevars;
+ $h->{binary}{_example} = "/usr/bin/fping6";
+ return $h;
}
-
+
1;
diff --git a/lib/probes/IOSPing.pm b/lib/probes/IOSPing.pm
index 3b71148..d73d046 100644
--- a/lib/probes/IOSPing.pm
+++ b/lib/probes/IOSPing.pm
@@ -1,62 +1,38 @@
package probes::IOSPing;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::IOSPing - Cisco IOS Probe for SmokePing
-
-=head1 SYNOPSIS
-
- *** Probes ***
- + IOSPing
- binary = /usr/bin/remsh
- packetsize = 1024
- forks = 1
-
- ++ PROBE_CONF
- ioshost = router
- iosuser = user
- iosint = source_address
-
-=head1 DESCRIPTION
-
-Integrates Cisco IOS as a probe into smokeping. Uses the rsh / remsh
-protocol to run a ping from an IOS device.
-
-=head1 OPTIONS
-
-The binary and ioshost options are mandatory.
+This is a Smokeping probe module. Please use the command
-The binary option specifies the path of the binary to be used to
-connect to the IOS device. Commonly used binaries are /usr/bin/rsh
-and /usr/bin/remsh, although any script or binary should work if can
-be called as
-
- /path/to/binary [ -l user ] router ping
+C<smokeping -man probes::IOSPing>
-to produce the IOS ping dialog on stdin & stdout.
+to view the documentation or the command
-The (optional) packetsize option lets you configure the packetsize for
-the pings sent.
+C<smokeping -makepod probes::IOSPing>
-The (optional) forks options lets you configure the number of
-simultaneous remote pings to be run. NB Some IOS devices have a
-maximum of 5 VTYs available, so be careful not to hit a limit.
+to generate the POD document.
-The ioshost option specifies the IOS device which should be used for
-the ping.
+=cut
-The (optional) iosuser option allows you to specify the remote
-username the IOS device. If this option is omitted, the username
-defaults to the default user used by the remsh command (usually the
-user running the remsh command, ie the user running SmokePing).
+use strict;
+use base qw(probes::basefork);
+use IPC::Open2;
+use Symbol;
+use Carp;
-The (optional) iosint option allows you to specify the source address
-or interface in the IOS device. The value should be an IP address or
-an interface name such as "Ethernet 1/0". If this option is omitted,
-the IOS device will pick the IP address of the outbound interface to
-use.
+my $e = "=";
-=head1 IOS CONFIGURATION
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::IOSPing - Cisco IOS Probe for SmokePing
+DOC
+ description => <<DOC,
+Integrates Cisco IOS as a probe into smokeping. Uses the rsh / remsh
+protocol to run a ping from an IOS device.
+DOC
+ notes => <<DOC,
+=head2 IOS Configuration
The IOS device must have rsh enabled and an appropriate trust defined,
eg:
@@ -66,14 +42,15 @@ eg:
ip rcmd remote-host smoke 192.168.1.2 smoke enable
!
-=head1 NOTES
+Some IOS devices have a maximum of 5 VTYs available, so be careful not to
+hit a limit with the 'forks' variable.
-=head2 Password authentication
+${e}head2 Password authentication
It is not possible to use password authentication with rsh or remsh
due to fundamental limitations of the protocol.
-=head2 Ping packet size
+${e}head2 Ping packet size
The FPing manpage has the following to say on the topic of ping packet
size:
@@ -85,22 +62,16 @@ header (normally 20 bytes) and ICMP header (8 bytes), so the minimum
total size is 40 bytes. Default is 56, as in ping. Maximum is the
theoretical maximum IP datagram size (64K), though most systems limit
this to a smaller, system-dependent number.
-
-=head1 AUTHOR
-
+DOC
+ authors => <<'DOC',
Paul J Murphy <paul@murph.org>
based on probes::FPing by
Tobias Oetiker <tobi@oetiker.ch>
-
-=cut
-
-use strict;
-use base qw(probes::basefork);
-use IPC::Open2;
-use Symbol;
-use Carp;
+DOC
+ }
+}
sub new($$$)
{
@@ -110,16 +81,6 @@ sub new($$$)
# no need for this if we run as a cgi
unless ( $ENV{SERVER_SOFTWARE} ) {
- croak "ERROR: IOSPing packetsize must be between 12 and 64000"
- if $self->{properties}{packetsize} and
- ( $self->{properties}{packetsize} < 12 or $self->{properties}{packetsize} > 64000 );
-
- croak "ERROR: IOSPing 'binary' not defined in IOSPing probe definition"
- unless defined $self->{properties}{binary};
-
- croak "ERROR: IOSPing 'binary' does not point to an executable"
- unless -f $self->{properties}{binary} and -x $self->{properties}{binary};
-
$self->{pingfactor} = 1000; # Gives us a good-guess default
print "### assuming you are using an IOS reporting in miliseconds\n";
};
@@ -129,14 +90,14 @@ sub new($$$)
sub ProbeDesc($){
my $self = shift;
- my $bytes = $self->{properties}{packetsize} || 56;
+ my $bytes = $self->{properties}{packetsize};
return "Cisco IOS - ICMP Echo Pings ($bytes Bytes)";
}
sub pingone ($$){
my $self = shift;
my $target = shift;
- my $bytes = $self->{properties}{packetsize} || 56;
+ my $bytes = $self->{properties}{packetsize};
# do NOT call superclass ... the ping method MUST be overwriten
my %upd;
my $inh = gensym;
@@ -144,9 +105,6 @@ sub pingone ($$){
my @args = ();
my $pings = $self->pings($target);
- croak "ERROR: IOSPing 'ioshost' not defined"
- unless defined $target->{vars}{ioshost};
-
push(@args,$self->{properties}{binary});
push(@args,'-l',$target->{vars}{iosuser})
if defined $target->{vars}{iosuser};
@@ -229,4 +187,76 @@ sub pingone ($$){
return @times;
}
+sub probevars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::probevars, {
+ _mandatory => ['binary'],
+ binary => {
+ _doc => <<DOC,
+The binary option specifies the path of the binary to be used to
+connect to the IOS device. Commonly used binaries are /usr/bin/rsh
+and /usr/bin/remsh, although any script or binary should work if can
+be called as
+
+ /path/to/binary [ -l user ] router ping
+
+to produce the IOS ping dialog on stdin & stdout.
+DOC
+ _example => '/usr/bin/rsh',
+ _sub => sub {
+ my $val = shift;
+ -x $val or return "ERROR: binary '$val' is not executable";
+ return undef;
+ },
+ },
+ packetsize => {
+ _doc => <<DOC,
+The (optional) packetsize option lets you configure the packetsize for
+the pings sent.
+DOC
+ _default => 56,
+ _re => '\d+',
+ _sub => sub {
+ my $val = shift;
+ return "ERROR: packetsize must be between 12 and 64000"
+ unless $val >= 12 and $val <= 64000;
+ return undef;
+ },
+ },
+ });
+}
+
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ _mandatory => [ 'ioshost' ],
+ ioshost => {
+ _doc => <<DOC,
+The ioshost option specifies the IOS device which should be used for
+the ping.
+DOC
+ _example => 'my.cisco.router',
+ },
+ iosuser => {
+ _doc => <<DOC,
+The (optional) iosuser option allows you to specify the remote
+username the IOS device. If this option is omitted, the username
+defaults to the default user used by the remsh command (usually the
+user running the remsh command, ie the user running SmokePing).
+DOC
+ _example => 'admin',
+ },
+ iosint => {
+ _doc => <<DOC,
+The (optional) iosint option allows you to specify the source address
+or interface in the IOS device. The value should be an IP address or
+an interface name such as "Ethernet 1/0". If this option is omitted,
+the IOS device will pick the IP address of the outbound interface to
+use.
+DOC
+ _example => 'Ethernet 1/0',
+ },
+ });
+}
+
1;
diff --git a/lib/probes/LDAP.pm b/lib/probes/LDAP.pm
index b7e5342..2bb966f 100644
--- a/lib/probes/LDAP.pm
+++ b/lib/probes/LDAP.pm
@@ -1,41 +1,37 @@
package probes::LDAP;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::LDAP - a LDAP probe for SmokePing
-
-=head1 OVERVIEW
+This is a Smokeping probe module. Please use the command
-Measures LDAP search latency for SmkoePing
+C<smokeping -man probes::LDAP>
-=head1 SYNOPSYS
+to view the documentation or the command
- *** Probes ***
- + LDAP
+C<smokeping -makepod probes::LDAP>
- passwordfile = /usr/share/smokeping/etc/password # optional
- sleeptime = 0.5 # optional, 1 second by default
+to generate the POD document.
- *** Targets ***
+=cut
- probe = LDAP
+use strict;
+use probes::passwordchecker;
+use Net::LDAP;
+use Time::HiRes qw(gettimeofday sleep);
+use base qw(probes::passwordchecker);
+use IO::Socket::SSL;
- + PROBE_CONF
- port = 389 # optional
- version = 3 # optional
- start_tls = 1 # disabled by default
- timeout = 60 # optional
-
- base = dc=foo,dc=bar # optional
- filter = uid=testuser # the actual search
- attrs = uid,someotherattr
-
- # if binddn isn't present, the LDAP bind is unauthenticated
- binddn = uid=testuser,dc=foo,dc=bar
- password = mypass # if not present in <passwordfile>
-
-=head1 DESCRIPTION
+my $DEFAULTINTERVAL = 1;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::LDAP - a LDAP probe for SmokePing
+DOC
+ overview => <<DOC,
+Measures LDAP search latency for SmokePing
+DOC
+ description => <<DOC,
This probe measures LDAP query latency for SmokePing.
The query is specified by the target-specific variable `filter' and,
optionally, by the target-specific variable `base'. The attributes
@@ -54,57 +50,96 @@ The location of this file is given in the probe-specific variable
of this file (summary: colon-separated triplets of the form
`<host>:<bind-dn>:<password>')
-The probe tries to be nice to the server and sleeps for the probe-specific
-variable `sleeptime' (one second by default) between each authentication
-request.
-
-=head1 AUTHOR
-
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
-
-=head1 BUGS
-
+The probe tries to be nice to the server and does not send authentication
+requests more frequently than once every X seconds, where X is the value
+of the target-specific "min_interval" variable ($DEFAULTINTERVAL by default).
+DOC
+ authors => <<'DOC',
+Niko Tyni <ntyni@iki.fi>
+DOC
+ bugs => <<DOC,
There should be a way of specifying TLS options, such as the certificates
involved etc.
The probe has an ugly way of working around the fact that the
IO::Socket::SSL class complains if start_tls() is done more than once
in the same program. But It Works For Me (tm).
-
-=cut
-
-use strict;
-use probes::passwordchecker;
-use Net::LDAP;
-use Time::HiRes qw(gettimeofday sleep);
-use base qw(probes::passwordchecker);
-use IO::Socket::SSL;
+DOC
+ }
+}
sub ProbeDesc {
return "LDAP queries";
}
+sub probevars {
+ my $class = shift;
+ my $h = $class->SUPER::probevars;
+ delete $h->{timeout};
+ return $h;
+}
+
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ _mandatory => [ 'filter' ],
+ port => {
+ _re => '\d+',
+ _doc => "TCP port of the LDAP server",
+ _example => 389,
+ },
+ version => {
+ _re => '\d+',
+ _doc => "The LDAP version to be used.",
+ _example => 3,
+ },
+ start_tls => {
+ _doc => "If true, encrypt the connection with the starttls command. Disabled by default.",
+ _example => "1",
+ },
+ timeout => {
+ _doc => "LDAP query timeout in seconds.",
+ _re => '\d+',
+ _example => 10,
+ _default => 5,
+ },
+ base => {
+ _doc => "The base to be used in the LDAP query",
+ _example => "dc=foo,dc=bar",
+ },
+ filter => {
+ _doc => "The actual search to be made",
+ _example => "uid=testuser",
+ },
+ attrs => {
+ _doc => "The attributes queried.",
+ _example => "uid,someotherattr",
+ },
+ binddn => {
+ _doc => "If present, authenticate the LDAP bind with this DN.",
+ _example => "uid=testuser,dc=foo,dc=bar",
+ },
+ password => {
+ _doc => "The password to be used, if not present in <passwordfile>.",
+ _example => "mypass",
+ },
+ mininterval => {
+ _default => $DEFAULTINTERVAL,
+ _doc => "The minimum interval between each query sent, in (possibly fractional) second
+s.",
+ _re => '(\d*\.)?\d+',
+ },
+ });
+}
+
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = $class->SUPER::new(@_);
- my $sleeptime = $self->{properties}{sleeptime};
- $sleeptime = 1 unless defined $sleeptime;
- $self->sleeptime($sleeptime);
-
return $self;
}
-sub sleeptime {
- my $self = shift;
- my $newval = shift;
-
- $self->{sleeptime} = $newval if defined $newval;
- return $self->{sleeptime};
-}
-
-
sub pingone {
my $self = shift;
my $target = shift;
@@ -114,11 +149,21 @@ sub pingone {
my $version = $vars->{version} || 3;
my $port = $vars->{port};
+ my $mininterval = $vars->{mininterval};
+
my $binddn = $vars->{binddn};
my $timeout = $vars->{timeout};
- my $password = $vars->{password} || $self->password($host, $binddn) if defined $binddn;
+ my $password;
+ if (defined $binddn) {
+ $password = $self->password($host, $binddn);
+ if (defined $vars->{password} and
+ $vars->{password} ne ($self->{properties}{password}||"")) {
+ $password = $vars->{password};
+ }
+ $password ||= $self->{properties}{password};
+ }
my $start_tls = $vars->{start_tls};
@@ -128,14 +173,20 @@ sub pingone {
my $attrs = $vars->{attrs};
- my @attrs = split(/,/, $attrs);
+ my @attrs = split(/,/, $attrs||"");
+ my $attrsref = @attrs ? \@attrs : undef;
my @times;
+ my $start;
for (1..$self->pings($target)) {
+ if (defined $start) {
+ my $elapsed = gettimeofday() - $start;
+ my $timeleft = $mininterval - $elapsed;
+ sleep $timeleft if $timeleft > 0;
+ }
local $IO::Socket::SSL::SSL_Context_obj; # ugly but necessary
- sleep $self->sleeptime unless $_ == 1; # be nice
- my $start = gettimeofday();
+ $start = gettimeofday();
my $ldap = new Net::LDAP($host, port => $port, version => $version, timeout => $timeout)
or do {
$self->do_log("connection error on $host: $!");
@@ -163,7 +214,7 @@ sub pingone {
$ldap->unbind;
next;
};
- $mesg = $ldap->search(base => $base, filter => $filter, attrs => [ @attrs ]);
+ $mesg = $ldap->search(base => $base, filter => $filter, attrs => $attrsref);
$mesg->code and do {
$self->do_log("filter error on $host: " . $mesg->error);
$ldap->unbind;
diff --git a/lib/probes/Radius.pm b/lib/probes/Radius.pm
index 2c4fb96..6d0705b 100644
--- a/lib/probes/Radius.pm
+++ b/lib/probes/Radius.pm
@@ -1,55 +1,54 @@
package probes::Radius;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::Radius - a RADIUS authentication probe for SmokePing
-
-=head1 OVERVIEW
-
-Measures RADIUS authentication latency for SmokePing
+This is a Smokeping probe module. Please use the command
-=head1 SYNOPSYS
+C<smokeping -man probes::Radius>
- *** Probes ***
- + Radius
+to view the documentation or the command
- passwordfile = /usr/share/smokeping/etc/password
- secretfile = /etc/raddb/secret
- sleeptime = 0.5 # optional, 1 second by default
- username = test-user # optional, overridden by target
- password = test-password # optional, overridden by target
- secret = test-secret # optional, overridden by target
+C<smokeping -makepod probes::Radius>
- *** Targets ***
+to generate the POD document.
- probe = Radius
+=cut
- + PROBE_CONF
- username = testuser
- secret = myRadiusSecret # if not present in <secretfile>
- password = testuserPass # if not present in <passwordfile>
- port = 1645 # optional
- nas_ip_address = 1.2.3.4 # optional
+use strict;
+use base qw(probes::passwordchecker);
+use Authen::Radius;
+use Time::HiRes qw(gettimeofday sleep);
+use Carp;
-=head1 DESCRIPTION
+my $DEFAULTINTERVAL = 1;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::Radius - a RADIUS authentication probe for SmokePing
+DOC
+ overview => <<DOC,
+Measures RADIUS authentication latency for SmokePing
+DOC
+ description => <<DOC,
This probe measures RADIUS (RFC 2865) authentication latency for SmokePing.
The username to be tested is specified in either the probe-specific or the
target-specific variable `username', with the target-specific one overriding
the probe-specific one.
-The password can be specified either (in order of precedence, with the latter
-overriding the former) in the probe-specific variable `password', in the
-target-specific variable `password' or in an external file. The location of
-this file is given in the probe-specific variable `passwordfile'. See
-probes::passwordchecker(3pm) for the format of this file (summary:
-colon-separated triplets of the form `<host>:<username>:<password>')
+The password can be specified either (in order of precedence, with
+the latter overriding the former) in the probe-specific variable
+`password', in an external file or in the target-specific variable
+`password'. The location of this file is given in the probe-specific
+variable `passwordfile'. See probes::passwordchecker(3pm) for the
+format of this file (summary: colon-separated triplets of the form
+`<host>:<username>:<password>')
The RADIUS protocol requires a shared secret between the server and the client.
This secret can be specified either (in order of precedence, with the latter
-overriding the former) in the probe-specific variable `secret', in the
-target-specific variable `secret' or in an external file.
+overriding the former) in the probe-specific variable `secret', in an external file
+or in the target-specific variable `secret'.
This external file is located by the probe-specific variable `secretfile', and it should
contain whitespace-separated pairs of the form `<host> <secret>'. Comments and blank lines
are OK.
@@ -58,26 +57,18 @@ If the optional probe-specific variable `nas_ip_address' is specified, its
value is inserted into the authentication requests as the `NAS-IP-Address'
RADIUS attribute.
-The probe tries to be nice to the server and sleeps for the probe-specific
-variable `sleeptime' (one second by default) between each authentication
-request.
-
-=head1 AUTHOR
-
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
-
-=head1 BUGS
-
+The probe tries to be nice to the server and does not send authentication
+requests more frequently than once every X seconds, where X is the value
+of the target-specific "min_interval" variable ($DEFAULTINTERVAL by default).
+DOC
+ authors => <<'DOC',
+Niko Tyni <ntyni@iki.fi>
+DOC
+ bugs => <<DOC,
There should be a more general way of specifying RADIUS attributes.
-
-=cut
-
-use strict;
-use probes::passwordchecker;
-use base qw(probes::passwordchecker);
-use Authen::Radius;
-use Time::HiRes qw(gettimeofday sleep);
-use Carp;
+DOC
+ }
+}
sub ProbeDesc {
return "RADIUS queries";
@@ -91,6 +82,10 @@ sub new {
# no need for this if we run as a cgi
unless ($ENV{SERVER_SOFTWARE}) {
if (defined $self->{properties}{secretfile}) {
+ my @stat = stat($self->{properties}{secretfile});
+ my $mode = $stat[2];
+ carp("Warning: secret file $self->{properties}{secretfile} is world-readable\n")
+ if defined $mode and $mode & 04;
open(S, "<$self->{properties}{secretfile}")
or croak("Error opening specified secret file $self->{properties}{secretfile}: $!");
while (<S>) {
@@ -105,10 +100,6 @@ sub new {
close S;
}
- my $sleeptime = $self->{properties}{sleeptime};
- $sleeptime = 1 unless defined $sleeptime;
- $self->sleeptime($sleeptime);
-
}
return $self;
@@ -123,21 +114,21 @@ sub secret {
return $self->{secret}{$host};
}
-sub sleeptime {
- my $self = shift;
- my $newval = shift;
-
- $self->{sleeptime} = $newval if defined $newval;
- return $self->{sleeptime};
-}
-
sub pingone {
my $self = shift;
my $target = shift;
my $host = $target->{addr};
my $vars = $target->{vars};
- my $username = $vars->{username} || $self->{properties}->{username};
- my $secret = $vars->{secret} || $self->secret($host) || $self->{properties}->{secret};
+ my $mininterval = $vars->{mininterval};
+ my $username = $vars->{username};
+ my $secret = $self->secret($host);
+ if (defined $vars->{secret} and
+ $vars->{secret} ne ($self->{properties}{secret}||"")) {
+ $secret = $vars->{secret};
+ }
+ $secret ||= $self->{properties}{secret};
+
+ my $timeout = $vars->{timeout};
$self->do_log("Missing RADIUS secret for $host"), return
unless defined $secret;
@@ -145,17 +136,27 @@ sub pingone {
$self->do_log("Missing RADIUS username for $host"), return
unless defined $username;
- my $password = $vars->{password} || $self->password($host, $username) || $self->{properties}->{password};
-
- my $port = $vars->{port};
- $host .= ":$port" if defined $port;
+ my $password = $self->password($host, $username);
+ if (defined $vars->{password} and
+ $vars->{password} ne ($self->{properties}{password}||"")) {
+ $password = $vars->{password};
+ }
+ $password ||= $self->{properties}{password};
$self->do_log("Missing RADIUS password for $host/$username"), return
unless defined $password;
+ my $port = $vars->{port};
+ $host .= ":$port" if defined $port;
+
my @times;
+ my $elapsed;
for (1..$self->pings($target)) {
- my $r = new Authen::Radius(Host => $host, Secret => $secret);
+ if (defined $elapsed) {
+ my $timeleft = $mininterval - $elapsed;
+ sleep $timeleft if $timeleft > 0;
+ }
+ my $r = new Authen::Radius(Host => $host, Secret => $secret, TimeOut => $timeout);
$r->add_attributes(
{ Name => 1, Value => $username, Type => 'string' },
{ Name => 2, Value => $password, Type => 'string' },
@@ -172,13 +173,76 @@ sub pingone {
$result = "OK" if $c == ACCESS_ACCEPT;
$result = "fail" if $c == ACCESS_REJECT;
} else {
- $result = "no reply";
+ if (defined $r->get_error) {
+ $result = "error: " . $r->strerror;
+ } else {
+ $result = "no reply";
+ }
}
- $self->do_debug("$host: radius query $_: $result, " . ($end - $start));
- push @times, $end - $start if (defined $c and $c == ACCESS_ACCEPT);
- sleep $self->sleeptime; # be nice
+ $elapsed = $end - $start;
+ $self->do_debug("$host: radius query $_: $result, $elapsed");
+ push @times, $elapsed if (defined $c and $c == ACCESS_ACCEPT);
}
return sort { $a <=> $b } @times;
}
+sub probevars {
+ my $class = shift;
+ my $h = $class->SUPER::probevars;
+ delete $h->{timeout};
+ return $class->_makevars($h, {
+ secretfile => {
+ _doc => <<DOC,
+A file containing the RADIUS shared secrets for the targets. It should contain
+whitespace-separated pairs of the form `<host> <secret>'. Comments and blank lines
+are OK.
+DOC
+ _example => '/another/place/secret',
+ _sub => sub {
+ my $val = shift;
+ -r $val or return "ERROR: secret file $val is not readable.";
+ return undef;
+ },
+ },
+ });
+}
+
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ _mandatory => [ 'username' ],
+ username => {
+ _doc => 'The username to be tested.',
+ _example => 'test-user',
+ },
+ password => {
+ _doc => 'The password for the user, if not present in the password file.',
+ _example => 'test-password',
+ },
+ secret => {
+ _doc => 'The RADIUS shared secret for the target, if not present in the secrets file.',
+ _example => 'test-secret',
+ },
+ nas_ip_address => {
+ _doc => 'The NAS-IP-Address RADIUS attribute for the authentication requests. Not needed everywhere.',
+ _example => '10.1.2.3',
+ },
+ mininterval => {
+ _default => $DEFAULTINTERVAL,
+ _doc => "The minimum interval between each authentication request sent, in (possibly fractional) seconds.",
+ _re => '(\d*\.)?\d+',
+ },
+ timeout => {
+ _default => 5,
+ _doc => "Timeout in seconds for the RADIUS queries.",
+ _re => '\d+',
+ },
+ port => {
+ _doc => 'The RADIUS port to be used',
+ _re => '\d+',
+ _example => 1645,
+ },
+ });
+}
+
1;
diff --git a/lib/probes/RemoteFPing.pm b/lib/probes/RemoteFPing.pm
index da87b6c..9f26fd3 100644
--- a/lib/probes/RemoteFPing.pm
+++ b/lib/probes/RemoteFPing.pm
@@ -1,57 +1,31 @@
package probes::RemoteFPing;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::RemoteFPing - Remote FPing Probe for SmokePing
+This is a Smokeping probe module. Please use the command
-=head1 SYNOPSIS
+C<smokeping -man probes::RemoteFPing>
- *** Probes ***
- + RemoteFPing
- binary = /usr/bin/ssh
- packetsize = 1024
- rhost = HostA.foobar.com
- ruser = foo
- rbinary = /usr/local/sbin/fping
+to view the documentation or the command
- *** Targets ***
- + Targetname
- Probe = RemoteFPing
- Menu = menuname
- Title = Remote Fping from HostA to HostB
- Host = HostB.barfoo.com
+C<smokeping -makepod probes::RemoteFPing>
+to generate the POD document.
-=head1 DESCRIPTION
+=cut
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::RemoteFPing - Remote FPing Probe for SmokePing
+DOC
+ description => <<DOC,
Integrates the remote execution of FPing via ssh/rsh into smokeping.
The variable B<binary> must point to your copy of the ssh/rsh program.
-
-=head1 OPTIONS
-
-The B<binary> and B<rhost> are mandatory. The B<binary> option
-specifies the path of the remote shell program (usually ssh,
-rsh or remsh). Any other script or binary that can be called as
-
- binary [ -l ruser ] rhost rbinary
-
-may be used.
-
-The (optional) B<packetsize> option lets you configure the packetsize
-for the pings sent.
-
-The B<rhost> option specifies the remote device from where fping will
-be launched.
-
-The (optional) B<ruser> option allows you to specify the remote user,
-if different from the one running the smokeping daemon.
-
-The (optional) B<rbinary> option allows you to specify the location of
-the remote fping binary. If not specified the probe will assume that
-fping is in the remote host's path.
-
-=head1 NOTES
-
+The variable B<rbinary> must point to your copy of the fping program
+at the remote end.
+DOC
+ notes => <<'DOC',
It is important to make sure that you can access the remote machine
without a password prompt, otherwise this probe will not work properly.
To test just try something like this:
@@ -61,104 +35,88 @@ To test just try something like this:
The next thing you see must be fping's output.
The B<rhost>, B<ruser> and B<rbinary> variables used to be configured in
-the PROBE_CONF section of the first target or its parents They were moved
+the Targets section of the first target or its parents They were moved
to the Probes section, because the variables aren't really target-specific
-(all the targets are measured with the same parameters). The PROBE_CONF
+(all the targets are measured with the same parameters). The Targets
sections aren't recognized anymore.
+DOC
+ authors => <<'DOC',
+ Luis F Balbinot <hades@inf.ufrgs.br>
-=head1 AUTHOR
+ Niko Tyni <ntyni@iki.fi>
-Luis F Balbinot <hades@inf.ufrgs.br>
+ derived from probes::FPing by
-based on probes::FPing by
-
-Tobias Oetiker <tobi@oetiker.ch>
-
-=cut
+ Tobias Oetiker <tobi@oetiker.ch>
+DOC
+ bugs => <<DOC
+This functionality should be in a generic 'remote execution' module
+so that it could be used for the other probes too.
+DOC
+ }
+}
use strict;
-use base qw(probes::base);
-use IPC::Open3;
-use Symbol;
-use Carp;
-
-sub new($$$) {
- my $proto = shift;
- my $class = ref($proto) || $proto;
- my $self = $class->SUPER::new(@_);
-
- # no need for this if we run as a cgi
- unless ( $ENV{SERVER_SOFTWARE} ) {
- croak "ERROR: RemoteFPing packetsize must be between 12 and 64000"
- if $self->{properties}{packetsize} and
- ( $self->{properties}{packetsize} < 12 or $self->{properties}{packetsize} > 64000 );
-
- croak "ERROR: RemoteFPing 'binary' not defined in RemoteFPing probe definition"
- unless defined $self->{properties}{binary};
-
- croak "ERROR: RemoteFPing 'binary' does not point to an executable"
- unless -f $self->{properties}{binary} and -x $self->{properties}{binary};
-
- croak "ERROR: RemoteFPing 'rhost' not defined in RemoteFPing probe definition. This might be because the configuration syntax has changed. See the RemoteFPing manual for details."
- unless defined $self->{properties}{rhost};
-
- $self->{pingfactor} = 1000; # Gives us a good-guess default
- print "### assuming you are using a remote fping copy reporting in milliseconds\n";
- };
-
- return $self;
-}
+use base qw(probes::FPing);
sub ProbeDesc($) {
my $self = shift;
- my $bytes = $self->{properties}{packetsize} || 56;
- return "Remote ICMP Echo Pings ($bytes Bytes)";
+ my $superdesc = $self->SUPER::ProbeDesc;
+ return "Remote $superdesc";
}
-sub ping ($) {
+sub binary {
my $self = shift;
-
- # do NOT call superclass ... the ping method MUST be overwriten
- my %upd;
- my $inh = gensym;
- my $outh = gensym;
- my $errh = gensym;
- # pinging nothing is pointless
- return unless @{$self->addresses};
- my @bytes = ();
-
- push @bytes, "-b$self->{properties}{packetsize}" if $self->{properties}{packetsize};
-
- my @rargs;
+ my @ret = ( $self->SUPER::binary );
for my $what (qw(ruser rhost rbinary)) {
- my $prefix = ($what eq 'ruser' ? "-l" : "");
- if (defined $self->{properties}{$what}) {
- push @rargs, $prefix . $self->{properties}{$what};
- }
+ my $prefix = ($what eq 'ruser' ? "-l" : "");
+ if (defined $self->{properties}{$what}) {
+ push @ret, $prefix . $self->{properties}{$what};
+ }
}
+ return @ret;
+}
- my $query = "$self->{properties}{binary} @rargs @bytes -C " . $self->pings . " -q -B1 -i10 -r1 @{$self->addresses}";
-
- $self->do_debug("query=$query\n");
-
- my $pid = open3($inh,$outh,$errh,$query );
- my @times =() ;
- $self->{rtts}={};
- while (<$errh>) {
- chomp;
- next unless /^\S+\s+:\s+[\d\.]/; #filter out error messages from fping
- $self->do_debug("array element=$_ \n");
- @times = split /\s+/;
- my $ip = shift @times;
- next unless ':' eq shift @times; #drop the colon
- @times = map {sprintf "%.10e", $_ / $self->{pingfactor}} sort {$a <=> $b} grep {$_ ne "-"} @times;
- map { $self->{rtts}{$_} = [@times] } @{$self->{addrlookup}{$ip}} ;
- }
- waitpid $pid,0;
- close $inh;
- close $outh;
- close $errh;
- return @times;
+sub probevars {
+ my $class = shift;
+ my $h = $class->SUPER::probevars;
+ $h->{rbinary} = $h->{binary};
+ delete $h->{binary};
+ delete $h->{rbinary}{sub}; # we can't check the remote program's -x bit
+ @{$h->{_mandatory}} = map { $_ ne 'binary' ? $_ : 'rbinary' } @{$h->{_mandatory}};
+ return $class->_makevars($h, {
+ _mandatory => [ 'binary', 'rhost' ],
+ binary => {
+ _doc => <<DOC,
+This variable specifies the path of the remote shell program (usually ssh,
+rsh or remsh). Any other script or binary that can be called as
+
+binary [ -l ruser ] rhost rbinary
+
+may be used.
+DOC
+ _example => '/usr/bin/ssh',
+ _sub => sub {
+ my $val = shift;
+ -x $val or return "ERROR: binary '$val' is not executable";
+ return undef;
+ },
+ },
+ rhost => {
+ _doc => <<DOC,
+The B<rhost> option specifies the remote device from where fping will
+be launched.
+DOC
+ _example => 'my.pinger.host',
+ },
+ ruser => {
+ _doc => <<DOC,
+The (optional) B<ruser> option allows you to specify the remote user,
+if different from the one running the smokeping daemon.
+DOC
+ _example => 'foo',
+ },
+ });
}
1;
diff --git a/lib/probes/SSH.pm b/lib/probes/SSH.pm
index ede9c4c..f91a8d0 100644
--- a/lib/probes/SSH.pm
+++ b/lib/probes/SSH.pm
@@ -1,59 +1,16 @@
package probes::SSH;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::SSH - Secure Shell Probe for SmokePing
-
-=head1 SYNOPSIS
-
- *** Probes ***
- + SSH
- binary = /usr/bin/ssh-keyscan
-
- *** Targets ***
- probe = SSH
- forks = 10
-
- + First
- menu = First
- title = First Target
- # ....
-
-=head1 DESCRIPTION
-
-Integrates ssh-keyscan as a probe into smokeping. The variable B<binary> must
-point to your copy of the ssh-keyscan program. If it is not installed on
-your system yet, you should install openssh >= 3.8p1
-
-The Probe asks the given host n-times for it's public key. Where n is
-the amount specified in the config File.
-
-Supported probe-specific variables:
-
-=over
-
-=item binary
-
-The location of your ssh-keyscan binary.
-
-=item forks
+This is a Smokeping probe module. Please use the command
-The number of concurrent processes to be run. See probes::basefork(3pm)
-for details.
+C<smokeping -man probes::SSH>
-=back
+to view the documentation or the command
-Supported target-level probe variables:
-
-=over
-
-=back
-
-
-=head1 AUTHOR
-
-Christian Recktenwald<lt>smokeping-contact@citecs.de<gt>
+C<smokeping -makepod probes::SSH>
+to generate the POD document.
=cut
@@ -64,6 +21,25 @@ use Symbol;
use Carp;
use POSIX;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::SSH - Secure Shell Probe for SmokePing
+DOC
+ description => <<DOC,
+Integrates ssh-keyscan as a probe into smokeping. The variable B<binary> must
+point to your copy of the ssh-keyscan program. If it is not installed on
+your system yet, you should install openssh >= 3.8p1
+
+The Probe asks the given host n-times for it's public key. Where n is
+the amount specified in the config File.
+DOC
+ authors => <<'DOC',
+Christian Recktenwald <smokeping-contact@citecs.de>
+DOC
+ }
+}
+
my $ssh_re=qr/^# \S+ SSH-/i;
sub new($$$)
@@ -75,11 +51,6 @@ sub new($$$)
# no need for this if we run as a cgi
unless ( $ENV{SERVER_SOFTWARE} ) {
- croak "ERROR: SSH 'binary' not defined in SSH probe definition"
- unless defined $self->{properties}{binary};
-
- croak "ERROR: SSH 'binary' does not point to an executable"
- unless -f $self->{properties}{binary} and -x $self->{properties}{binary};
my $call = "$self->{properties}{binary} -t rsa localhost";
my $return = `$call 2>&1`;
if ($return =~ m/$ssh_re/s){
@@ -134,4 +105,20 @@ sub pingone ($){
return @times;
}
+sub probevars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::probevars, {
+ _mandatory => [ 'binary' ],
+ binary => {
+ _doc => "The location of your ssh-keyscan binary.",
+ _example => '/usr/bin/ssh-keyscan',
+ _sub => sub {
+ my $val = shift;
+ -x $val or return "ERROR: binary '$val' is not executable";
+ return undef;
+ },
+ },
+ })
+}
+
1;
diff --git a/lib/probes/base.pm b/lib/probes/base.pm
index 79165f1..3101e01 100644
--- a/lib/probes/base.pm
+++ b/lib/probes/base.pm
@@ -1,17 +1,16 @@
package probes::base;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::base - Base Class for implementing SmokePing Probes
+This is a Smokeping probe module. Please use the command
-=head1 OVERVIEW
-
-For the time being, please use the probes::FPing for
-inspiration when implementing your own probes.
+C<smokeping -man probes::base>
-=head1 AUTHOR
+to view the documentation or the command
-Tobias Oetiker <tobi@oetiker.ch>
+C<smokeping -makepod probes::base>
+
+to generate the POD document.
=cut
@@ -24,6 +23,39 @@ $VERSION = 1.0;
use strict;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::base - Base Class for implementing SmokePing Probes
+DOC
+ overview => <<DOC,
+For the time being, please use the 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;
@@ -214,4 +246,155 @@ sub target_count {
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/^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;
diff --git a/lib/probes/basefork.pm b/lib/probes/basefork.pm
index 9fd3f14..0eb213b 100644
--- a/lib/probes/basefork.pm
+++ b/lib/probes/basefork.pm
@@ -1,50 +1,41 @@
package probes::basefork;
-my $DEFAULTFORKS = 5;
-
-=head1 NAME
-
-probes::basefork - Yet Another Base Class for implementing SmokePing Probes
-
-=head1 OVERVIEW
-
-Like probes::basevars, but supports the probe-specific property `forks'
-to determine how many processes should be run concurrently. The
-targets are pinged one at a time, and the number of pings sent can vary
-between targets.
+=head1 301 Moved Permanently
-=head1 SYNOPSYS
+This is a Smokeping probe module. Please use the command
- *** Probes ***
+C<smokeping -man probes::basefork>
- + MyForkingProbe
- # run this many concurrent processes
- forks = 10
- # how long does a single 'ping' take
- timeout = 10
- # how many pings to send
- pings = 10
+to view the documentation or the command
- + MyOtherForkingProbe
- # we don't want any concurrent processes at all for some reason.
- forks = 1
+C<smokeping -makepod probes::basefork>
- *** Targets ***
+to generate the POD document.
- menu = First
- title = First
- host = firsthost
- probe = MyForkingProbe
+=cut
- menu = Second
- title = Second
- host = secondhost
- probe = MyForkingProbe
- +PROBE_CONF
- pings = 20
+use strict;
+use base qw(probes::basevars);
+use Symbol;
+use Carp;
+use IO::Select;
+use POSIX; # for ceil() and floor()
+use Config; # for signal names
-=head1 DESCRIPTION
+my $DEFAULTFORKS = 5;
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::basefork - Yet Another Base Class for implementing SmokePing Probes
+DOC
+ overview => <<DOC,
+Like probes::basevars, but supports the probe-specific property `forks'
+to determine how many processes should be run concurrently. The
+targets are pinged one at a time, and the number of pings sent can vary
+between targets.
+DOC
+ description => <<DOC,
Not all pinger programs support testing multiple hosts in a single go like
fping(1). If the measurement takes long enough, there may be not enough time
perform all the tests in the time available. For example, if the test takes
@@ -60,7 +51,7 @@ the target that is to be measured. The contents of the hash are
described in I<probes::basevars>(3pm).
The number of concurrent processes is determined by the probe-specific
-variable `forks' and is 5 by default. If there are more
+variable `forks' and is $DEFAULTFORKS by default. If there are more
targets than this value, another round of forks is done after the first
processes are finished. This continues until all the targets have been
tested.
@@ -69,37 +60,24 @@ The timeout in which each child has to finish is set to 5 seconds
multiplied by the maximum number of 'pings' of the targets. You can set
the base timeout differently if you want to, using the timeout property
of the probe in the master config file (this again will be multiplied
-by the maximum number of pings). The probe itself can also override the
-default by providing a TimeOut method which returns an integer.
+by the maximum number of pings). The probe itself can also provide
+another default value if desired by modifying the _default value of
+the timeout variable.
If the child isn't finished when the timeout occurs, it
will be killed along with any processes it has started.
-The number of pings sent can be specified in the probe-specific variable
-'pings', and it can be overridden by each target in the 'PROBE_CONF'
-section.
-
-=head1 AUTHOR
-
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
-
-=head1 BUGS
-
-The timeout code has only been tested on Linux.
-
-=head1 SEE ALSO
-
+The number of pings sent can be specified in the target-specific variable
+'pings'.
+DOC
+ authors => <<'DOC',
+Niko Tyni <ntyni@iki.fi>
+DOC
+ see_also => <<DOC,
probes::basevars(3pm), probes::EchoPing(3pm)
-
-=cut
-
-use strict;
-use base qw(probes::basevars);
-use Symbol;
-use Carp;
-use IO::Select;
-use POSIX; # for ceil() and floor()
-use Config; # for signal names
+DOC
+ }
+}
my %signo;
my @signame;
@@ -122,9 +100,41 @@ sub pingone {
croak "pingone: this must be overridden by the subclass";
}
-sub TimeOut {
- # probes which require more time may want to provide their own implementation.
- return 5;
+sub probevars {
+ my $class = shift;
+ my $h = $class->SUPER::probevars;
+ delete $h->{pings};
+ return $class->_makevars($h, {
+ forks => {
+ _re => '\d+',
+ _example => 5,
+ _doc => "Run this many concurrent processes at maximum",
+ _default => $DEFAULTFORKS,
+ },
+ timeout => {
+ _re => '\d+',
+ _example => 15,
+ _default => 5,
+ _doc => "How long a single 'ping' takes at maximum",
+ },
+ });
+}
+
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ pings => {
+ _re => '\d+',
+ _example => 5,
+ _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
+ },
+ });
}
sub ping {
@@ -133,20 +143,25 @@ sub ping {
my @targets = @{$self->targets};
return unless @targets;
- my $forks = $self->{properties}{forks} || $DEFAULTFORKS;
-
- my $timeout = $self->{properties}{timeout};
- unless (defined $timeout and $timeout > 0) {
- my $maxpings = 0;
- for (@targets) {
- my $p = $self->pings($_);
- $maxpings = $p if $p > $maxpings;
- }
- $timeout = $maxpings * $self->TimeOut();
+ my $forks = $self->{properties}{forks};
+
+ my $maxpings = 0;
+ my $maxtimeout = $self->{properties}{timeout};
+ for (@targets) {
+ my $p = $self->pings($_);
+ $maxpings = $p if $p > $maxpings;
+ # some probes have a target-specific timeout variable
+ # dig out the maximum timeout
+ my $t = $_->{vars}{timeout};
+ $maxtimeout = $t if $t > $maxtimeout;
}
+ # we add 1 so that the probes doing their own timeout handling
+ # have time to do it even in the worst case
+ my $timeout = $maxpings * $maxtimeout + 1;
+
$self->{rtts}={};
- $self->do_debug("forks $forks, timeout per target $timeout");
+ $self->do_debug("forks $forks, timeout for each target $timeout");
while (@targets) {
my %targetlookup;
@@ -239,4 +254,13 @@ sub ProbeDesc {
return "Probe that can fork and doesn't override the ProbeDesc method";
}
+sub pod_variables {
+ my $class = shift;
+ my $pod = $class->SUPER::pod_variables;
+ my $targetvars = $class->targetvars;
+ $pod .= "Supported target-specific variables:\n\n";
+ $pod .= $class->_pod_variables($targetvars);
+ return $pod;
+}
+
1;
diff --git a/lib/probes/basevars.pm b/lib/probes/basevars.pm
index 19f21e0..8862395 100644
--- a/lib/probes/basevars.pm
+++ b/lib/probes/basevars.pm
@@ -1,84 +1,68 @@
package probes::basevars;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::basevars - Another Base Class for implementing SmokePing Probes
-
-=head1 OVERVIEW
-
-Like probes::base, but supports host-specific variables for the probe.
+This is a Smokeping probe module. Please use the command
-=head1 SYNOPSIS
+C<smokeping -man probes::basevars>
- *** Targets ***
+to view the documentation or the command
- menu = Top
- title = Top Page
+C<smokeping -makepod probes::basevars>
- + branch_1
- menu = First menu
- title = First title
- host = host1
- ++ PROBE_CONF
- # vars for host host1
- var1 = foo
- var2 = bar
-
- ++ branch_1_2
- menu = Second menu
- title = Second title
- host = host2
- +++ PROBE_CONF
- # vars for host host2
- # var1 and var2 are propagated from above, override var2
- var2 = fii
+to generate the POD document.
- + branch_2
- # var1 and var2 are undefined here
+=cut
-=head1 DESCRIPTION
+use strict;
+use probes::base;
+use base qw(probes::base);
+my $e = "=";
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::basevars - Another Base Class for implementing SmokePing Probes
+DOC
+ overview => <<DOC,
+Like probes::base, but supports host-specific variables for the probe.
+DOC
+ description => <<DOC,
Provides the method `targets' that returns a list of hashes.
The hashes contain the entries:
-=over
+${e}over
-=item addr
+${e}item addr
The address of the target.
-=item vars
+${e}item vars
A hash containing variables defined in the corresponding
-`PROBE_CONF' config section.
+config section.
-=item tree
+${e}item tree
The unique index that `probe::base' uses for targets.
There's also the method 'vars' that returns the abovementioned
hash corresponding to the 'tree' index parameter.
-=back
-
-=head1 AUTHOR
-
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
-
-=head1 BUGS
-
+${e}back
+DOC
+ authors => <<'DOC',
+Niko Tyni <ntyni@iki.fi>
+DOC
+ bugs => <<DOC,
Uses `probes::base' internals too much to be a derived class, but
I didn't want to touch the base class directly.
-
-=head1 SEE ALSO
-
+DOC
+ see_also => <<DOC,
probes::base(3pm), probes::EchoPing(3pm)
-
-=cut
-
-use strict;
-use probes::base;
-use base qw(probes::base);
+DOC
+ }
+}
sub add($$)
{
@@ -86,7 +70,7 @@ sub add($$)
my $tree = shift;
$self->{targets}{$tree} = shift;
- $self->{PROBE_CONF}{$tree} = $tree->{PROBE_CONF};
+ $self->{vars}{$tree} = { %{$self->{properties}}, %$tree };
}
sub targets {
@@ -100,8 +84,7 @@ sub targets {
for (@$addr) {
@{$copy{$_}} = @{$self->{addrlookup}{$_}} unless exists $copy{$_};
my $tree = pop @{$copy{$_}};
- push @targets, { addr => $_, vars => $self->{PROBE_CONF}{$tree},
- tree => $tree };
+ push @targets, { addr => $_, vars => $self->{vars}{$tree}, tree => $tree };
}
return \@targets;
}
@@ -109,7 +92,7 @@ sub targets {
sub vars {
my $self = shift;
my $tree = shift;
- return $self->{PROBE_CONF}{$tree};
+ return $self->{vars}{$tree};
}
sub ProbeDesc {
diff --git a/lib/probes/passwordchecker.pm b/lib/probes/passwordchecker.pm
index 8fad4f9..87d72eb 100644
--- a/lib/probes/passwordchecker.pm
+++ b/lib/probes/passwordchecker.pm
@@ -1,15 +1,37 @@
package probes::passwordchecker;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::passwordchecker - A Base Class for implementing SmokePing Probes
+This is a Smokeping probe module. Please use the command
+
+C<smokeping -man probes::passwordchecker>
+
+to view the documentation or the command
+
+C<smokeping -makepod probes::passwordchecker>
+
+to generate the POD document.
+
+=cut
-=head1 OVERVIEW
+use strict;
+use probes::basefork;
+use base qw(probes::basefork);
+use Carp;
+my $e = "=";
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::passwordchecker - A Base Class for implementing SmokePing Probes
+DOC
+ overview => <<DOC,
Like probes::basefork, but supports a probe-specific configuration file
for storing passwords and a method for accessing them.
+DOC
-=head1 SYNOPSYS
+ description => <<DOC,
+${e}head2 synopsys with more detail
SmokePing main configuration file:
@@ -26,7 +48,7 @@ The specified password file:
host2:sue:notasecreteither
-=head1 DESCRIPTION
+${e}head2 Actual description
In implementing authentication probes, it might not be desirable to store
the necessary cleartext passwords in the SmokePing main configuration
@@ -41,37 +63,47 @@ in the probe-specific variable `passwordfile'. The passwords can later
be accessed and modified by the B<password> method, that needs the corresponding
host and username as arguments.
-=head1 PASSWORD FILE FORMAT
+${e}head2 Password file format
The password file format is simply one line for each triplet of host,
username and password, separated from each other by colons (:).
Comment lines, starting with the `#' sign, are ignored, as well as
empty lines.
+DOC
+ authors => <<'DOC',
+Niko Tyni <ntyni@iki.fi>
+DOC
-=head1 AUTHOR
-
-Niko Tyni E<lt>ntyni@iki.fiE<gt>
-
-=head1 BUGS
-
+ bugs => <<DOC,
The need for storing cleartext passwords can be considered a bug in itself.
+DOC
-=head1 SEE ALSO
-
+ see_also => <<DOC,
probes::basefork(3pm), probes::Radius(3pm), probes::LDAP(3pm)
-
-=cut
-
-use strict;
-use probes::basefork;
-use base qw(probes::basefork);
-use Carp;
+DOC
+ }
+}
sub ProbeDesc {
return "probe that can fork, knows about passwords and doesn't override the ProbeDesc method";
}
+sub probevars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::probevars, {
+ passwordfile => {
+ _doc => "Location of the file containing usernames and passwords.",
+ _example => '/some/place/secret',
+ _sub => sub {
+ my $val = shift;
+ -r $val or return "ERROR: password file $val is not readable.";
+ return undef;
+ },
+ },
+ });
+}
+
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
diff --git a/lib/probes/skel.pm b/lib/probes/skel.pm
new file mode 100644
index 0000000..5438e1f
--- /dev/null
+++ b/lib/probes/skel.pm
@@ -0,0 +1,134 @@
+package probes::skel;
+
+=head1 301 Moved Permanently
+
+This is a Smokeping probe module. Please use the command
+
+C<smokeping -man probes::skel>
+
+to view the documentation or the command
+
+C<smokeping -makepod probes::skel>
+
+to generate the POD document.
+
+=cut
+
+use strict;
+use base qw(probes::basefork);
+# or, alternatively
+# use base qw(probes::base);
+use Carp;
+
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::skel - a skeleton for Smokeping Probes
+DOC
+ description => <<DOC,
+This is a non-functional module that is intended to act as a
+basis for creation of new probes. See the L<smokeping_extend>
+document for more information.
+DOC
+ authors => <<'DOC',
+ Niko Tyni <ntyni@iki.fi>,
+DOC
+ see_also => <<DOC
+The L<smokeping_extend> document
+DOC
+ };
+}
+
+sub new($$$)
+{
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = $class->SUPER::new(@_);
+
+ # no need for this if we run as a cgi
+ unless ( $ENV{SERVER_SOFTWARE} ) {
+ # if you have to test the program output
+ # or something like that, do it here
+ # and bail out if necessary
+ };
+
+ return $self;
+}
+
+# This is where you should declare your probe-specific variables.
+# The example shows the common case of checking the availability of
+# the specified binary.
+
+sub probevars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::probevars, {
+ #_mandatory => [ 'binary' ],
+ #binary => {
+ # _doc => "The location of your pingpong binary.",
+ # _example => '/usr/bin/pingpong',
+ # _sub => sub {
+ # my $val = shift;
+ # return "ERROR: pingpong 'binary' does not point to an executable"
+ # unless -f $val and -x _;
+ # return undef;
+ # },
+ #},
+ });
+}
+
+# Here's the place for target-specific variables
+
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ #weight => { _doc => "The weight of the pingpong ball in grams",
+ # _example => 15
+ #},
+ });
+}
+
+sub ProbeDesc($){
+ my $self = shift;
+ return "pingpong points";
+}
+
+# this is where the actual stuff happens
+# you can access the probe-specific variables
+# via the $self->{properties} hash and the
+# target-specific variables via $target->{vars}
+
+# If you based your class on 'probes::base',
+# you'd have to provide a "ping" method instead
+# of "pingone"
+
+sub pingone ($){
+ my $self = shift;
+ my $target = shift;
+
+ # my $binary = $self->{properties}{binary};
+ # my $weight = $target->{vars}{weight}
+ # my $count = $self->pings($target); # the number of pings for this targets
+
+ # ping one target
+
+ # execute a command and parse its output
+ # you should return a sorted array of the measured latency times
+ # it could go something like this:
+
+ my @times;
+
+ #for (1..$count) {
+ # open(P, "$cmd 2>&1 |") or croak("fork: $!");
+ # while (<P>) {
+ # /time: (\d+\.\d+)/ and push @times, $1;
+ # }
+ # close P;
+ #}
+
+
+ return @times;
+}
+
+# That's all, folks!
+
+1;
diff --git a/lib/probes/telnetIOSPing.pm b/lib/probes/telnetIOSPing.pm
index e591563..e0af7ac 100644
--- a/lib/probes/telnetIOSPing.pm
+++ b/lib/probes/telnetIOSPing.pm
@@ -1,67 +1,39 @@
package probes::telnetIOSPing;
-=head1 NAME
+=head1 301 Moved Permanently
-probes::telnetIOSPing - Cisco IOS Probe for SmokePing
-
-=head1 SYNOPSIS
-
- *** Probes ***
- + telnetIOSPing
- packetsize = 56
- forks = 1
-
- ++ PROBE_CONF
- iospass = password
- iosuser = user
- target = 192.168.1.1
- source = 192.168.2.1
- psource = 192.168.2.129
-
-=head1 DESCRIPTION
+This is a Smokeping probe module. Please use the command
-Integrates Cisco IOS as a probe into smokeping. Uses the telnet protocol
-to run a ping from an IOS device (source) to another device (target).
-This probe basically uses the "extended ping" of the Cisco IOS. You have
-the option to specify which interface the ping is sourced from as well.
+C<smokeping -man probes::telnetIOSPing>
-=head1 OPTIONS
+to view the documentation or the command
-The iosuser, iospass, source, and target options are mandatory.
-
-The (optional) packetsize option lets you configure the packetsize for
-the pings sent. The default size is 56.
+C<smokeping -makepod probes::telnetIOSPing>
-The (optional) forks options lets you configure the number of
-simultaneous remote pings to be run. NB Some IOS devices have a
-maximum of 5 VTYs available, so be careful not to hit a limit.
+to generate the POD document.
-The source option specifies the IOS device to which we telnet. This
-is an IP address of an IOS Device that you/your server:
- 1) Have the ability to telnet to
- 2) Have a valid username and password for
-
-The target option specifies the device you wish to ping from your IOS
-Device.
-
-The (optional) psource option specifies an alternate IP address or
-Interface from which you wish to source your pings from. Routers
-can have many many IP addresses, and interfaces. When you ping from a
-router you have the ability to choose which interface and/or which IP
-address the ping is sourced from. Specifying an IP/interface does not
-necessarily specify the interface from which the ping will leave, but
-will specify which address the packet(s) appear to come from. If this
-option is left out the IOS Device will source the packet automatically
-based on routing and/or metrics. If this doesn't make sense to you
-then just leave it out.
+=cut
-The iosuser option allows you to specify a username that has ping
-capability on the IOS Device.
+use strict;
-The iospass option allows you to specify the password for the username
-specified with the option iosuser.
+use base qw(probes::basefork);
+use Net::Telnet ();
+use Carp;
-=head1 IOS CONFIGURATION
+my $e = "=";
+sub pod_hash {
+ return {
+ name => <<DOC,
+probes::telnetIOSPing - Cisco IOS Probe for SmokePing
+DOC
+ description => <<DOC,
+Integrates Cisco IOS as a probe into smokeping. Uses the telnet protocol
+to run a ping from an IOS device (source) to another device (host).
+This probe basically uses the "extended ping" of the Cisco IOS. You have
+the option to specify which interface the ping is sourced from as well.
+DOC
+ notes => <<DOC,
+${e}head2 IOS configuration
The IOS device should have a username/password configured, as well as
the ability to connect to the VTY(s).
@@ -75,14 +47,15 @@ eg:
transport input telnet
!
-=head1 NOTES
+Some IOS devices have a maximum of 5 VTYs available, so be careful not
+to hit a limit with the 'forks' variable.
-=head2 Requirements
+${e}head2 Requirements
This module requires the Net::Telnet module for perl. This is usually
included on most newer OSs which include perl.
-=head2 Debugging
+${e}head2 Debugging
There is some VERY rudimentary debugging code built into this module (it's
based on the debugging code written into Net::Telnet). It will log
@@ -91,7 +64,7 @@ These files will be written out into your current working directory (CWD).
You can change the names of these files to something with more meaning to
you.
-=head2 Password authentication
+${e}head2 Password authentication
You should be advised that the authentication method of telnet uses
clear text transmissions...meaning that without proper network security
@@ -104,7 +77,7 @@ Having said this, don't be too scared of telnet. Remember, the
original IOSPing module used RSH, which is even more scary to use from
a security perspective.
-=head2 Ping packet size
+${e}head2 Ping packet size
The FPing manpage has the following to say on the topic of ping packet
size:
@@ -116,9 +89,8 @@ header (normally 20 bytes) and ICMP header (8 bytes), so the minimum
total size is 40 bytes. Default is 56, as in ping. Maximum is the
theoretical maximum IP datagram size (64K), though most systems limit
this to a smaller, system-dependent number.
-
-=head1 AUTHOR
-
+DOC
+ authors => <<'DOC',
John A Jackson <geonjay@infoave.net>
based HEAVILY on probes::IOSPing by
@@ -128,14 +100,9 @@ Paul J Murphy <paul@murph.org>
based on probes::FPing by
Tobias Oetiker <tobi@oetiker.ch>
-
-=cut
-
-use strict;
-
-use base qw(probes::basefork);
-use Net::Telnet ();
-use Carp;
+DOC
+ }
+}
sub new($$$)
{
@@ -145,10 +112,6 @@ sub new($$$)
# no need for this if we run as a cgi
unless ( $ENV{SERVER_SOFTWARE} ) {
- croak "ERROR: IOSPing packetsize must be between 12 and 64000"
- if $self->{properties}{packetsize} and
- ( $self->{properties}{packetsize} < 12 or $self->{properties}{packetsize} > 64000 );
-
$self->{pingfactor} = 1000; # Gives us a good-guess default
print "### assuming you are using an IOS reporting in miliseconds\n";
};
@@ -158,7 +121,7 @@ sub new($$$)
sub ProbeDesc($){
my $self = shift;
- my $bytes = $self->{properties}{packetsize} || 56;
+ my $bytes = $self->{properties}{packetsize};
return "InfoAve Cisco IOS - ICMP Echo Pings ($bytes Bytes)";
}
@@ -166,13 +129,13 @@ sub pingone ($$){
my $self = shift;
my $target = shift;
my $source = $target->{vars}{source};
- my $dest = $target->{vars}{target};
+ my $dest = $target->{vars}{host};
my $psource = $target->{vars}{psource} || "";
my $port = 23;
my @output = ();
my $login = $target->{vars}{iosuser};
my $pssword = $target->{vars}{iospass};
- my $bytes = $self->{properties}{packetsize} || 56;
+ my $bytes = $self->{properties}{packetsize};
my $pings = $self->pings($target);
# do NOT call superclass ... the ping method MUST be overwriten
@@ -252,4 +215,69 @@ sub pingone ($$){
return @times;
}
+sub probevars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::probevars, {
+ packetsize => {
+ _doc => <<DOC,
+The (optional) packetsize option lets you configure the packetsize for
+the pings sent.
+DOC
+ _default => 56,
+ _re => '\d+',
+ _sub => sub {
+ my $val = shift;
+ return "ERROR: packetsize must be between 12 and 64000"
+ unless $val >= 12 and $val <= 64000;
+ return undef;
+ },
+ },
+ });
+}
+
+sub targetvars {
+ my $class = shift;
+ return $class->_makevars($class->SUPER::targetvars, {
+ _mandatory => [ 'iosuser', 'iospass', 'source' ],
+ source => {
+ _doc => <<DOC,
+The source option specifies the IOS device to which we telnet. This
+is an IP address of an IOS Device that you/your server:
+ 1) Have the ability to telnet to
+ 2) Have a valid username and password for
+DOC
+ _example => "192.168.2.1",
+ },
+ psource => {
+ _doc => <<DOC,
+The (optional) psource option specifies an alternate IP address or
+Interface from which you wish to source your pings from. Routers
+can have many many IP addresses, and interfaces. When you ping from a
+router you have the ability to choose which interface and/or which IP
+address the ping is sourced from. Specifying an IP/interface does not
+necessarily specify the interface from which the ping will leave, but
+will specify which address the packet(s) appear to come from. If this
+option is left out the IOS Device will source the packet automatically
+based on routing and/or metrics. If this doesn't make sense to you
+then just leave it out.
+DOC
+ _example => "192.168.2.129",
+ },
+ iosuser => {
+ _doc => <<DOC,
+The iosuser option allows you to specify a username that has ping
+capability on the IOS Device.
+DOC
+ _example => 'user',
+ },
+ iospass => {
+ _doc => <<DOC,
+The iospass option allows you to specify the password for the username
+specified with the option iosuser.
+DOC
+ _example => 'password',
+ },
+ });
+}
+
1;