2009-06-05 04:27:33 +02:00
|
|
|
#!/usr/bin/perl -w
|
|
|
|
|
|
|
|
# Plugin to monitor offsets to multiple NTP peers.
|
|
|
|
# NB currently only works for IPv4 peers
|
|
|
|
#
|
|
|
|
# (c)2008 Chris Hastie: chris (at) oak (hyphen) wood (dot) co (dot) uk
|
|
|
|
#
|
|
|
|
# Parameters understood:
|
|
|
|
#
|
|
|
|
# config (required)
|
|
|
|
# autoconf (optional - used by munin-node-configure)
|
|
|
|
#
|
|
|
|
# Config variables:
|
|
|
|
#
|
|
|
|
# ntpq - path to ntpq program
|
|
|
|
#
|
|
|
|
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
# Change log
|
|
|
|
# v1.0.0 2008-07-21 Chris Hastie
|
|
|
|
# initial release
|
|
|
|
# v1.0.1 2009-06-05 Tony Hoyle
|
|
|
|
# ipv6 support. Remove dns lookups.
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# Magic markers - optional - used by installation scripts and
|
|
|
|
# munin-node-configure:
|
|
|
|
#
|
|
|
|
#%# family=contrib
|
|
|
|
#%# capabilities=autoconf
|
|
|
|
#
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
|
|
|
|
my $NTPQ = $ENV{ntpq} || "ntpq";
|
|
|
|
my $COMMAND = "$NTPQ -nc associations";
|
|
|
|
|
|
|
|
my $statedir = $ENV{statedir} || '/usr/local/var/munin/plugin-state';
|
|
|
|
my $statefile = "$statedir/ntp_peers.state";
|
|
|
|
|
|
|
|
# autoconf
|
|
|
|
if ($ARGV[0] and $ARGV[0] eq "autoconf") {
|
|
|
|
`$NTPQ -c help >/dev/null 2>/dev/null`;
|
|
|
|
if ($? eq "0") {
|
|
|
|
if (`$NTPQ -np | wc -l` > 0) {
|
|
|
|
print "yes\n";
|
|
|
|
exit 0;
|
|
|
|
} else {
|
|
|
|
print "no (unable to list peers)\n";
|
|
|
|
exit 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
print "no (ntpq not found)\n";
|
|
|
|
exit 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
my %peers;
|
|
|
|
|
|
|
|
# get data from ntpq
|
|
|
|
open(SERVICE, "$COMMAND |")
|
|
|
|
or die("Could not execute '$COMMAND': $!");
|
|
|
|
|
|
|
|
while (<SERVICE>) {
|
|
|
|
if(/^\s*\d+\s+(\d+)\s+/) {
|
|
|
|
my ($name, $offset) = &lookupip($1);
|
|
|
|
$peers{$name} = $offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(SERVICE);
|
|
|
|
|
|
|
|
# config
|
|
|
|
if ($ARGV[0] and $ARGV[0] eq 'config') {
|
|
|
|
print "graph_title NTP peer offsets\n";
|
|
|
|
print "graph_args --base 1000\n";
|
|
|
|
print "graph_vlabel ms\n";
|
2014-09-07 14:20:12 +02:00
|
|
|
print "graph_category time\n";
|
2009-06-05 04:27:33 +02:00
|
|
|
print "graph_info Offset (in ms) to the server's NTP peers\n";
|
|
|
|
print "graph_order ";
|
|
|
|
foreach my $key (sort keys %peers) {
|
|
|
|
print &sanitize_field($key) . " ";
|
|
|
|
}
|
|
|
|
print "\n";
|
|
|
|
foreach my $peer (keys %peers) {
|
|
|
|
print &sanitize_field($peer) . ".label " . $peer . "\n";
|
|
|
|
}
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
# send output
|
|
|
|
foreach my $peer (keys %peers) {
|
|
|
|
print &sanitize_field($peer) . ".value " . &getpeeroffset($peer) . "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
# create a valid munin field name from the hostname
|
|
|
|
sub sanitize_field () {
|
|
|
|
my $field = shift;
|
|
|
|
|
|
|
|
# replace illegal characters with an underscore
|
|
|
|
$field =~ s/[^A-Za-z0-9_]/_/g;
|
|
|
|
# prepend an underscore if name starts with a number
|
|
|
|
$field =~ s/^([^A-Za-z_])/_$1/;
|
|
|
|
|
|
|
|
# truncate to 19 characters
|
|
|
|
if (length($field) > 19) {
|
|
|
|
$field = substr($field, 0, 19);
|
|
|
|
}
|
|
|
|
return $field
|
|
|
|
}
|
|
|
|
|
|
|
|
# get an IP address from the underscore escaped
|
|
|
|
# value of env.hostname_<key>
|
|
|
|
sub desanitize_field () {
|
|
|
|
my $field = shift;
|
|
|
|
$field =~ s/_/\./g;
|
|
|
|
return $field
|
|
|
|
}
|
|
|
|
|
|
|
|
# Get name, offset info for peers
|
|
|
|
# It would be more efficient to use mrv here to avoid rerunning ntpq
|
|
|
|
sub lookupip() {
|
|
|
|
my $assocID = shift;
|
|
|
|
my $CMD = "$NTPQ -c \"rv $assocID srcadr,offset\"";
|
|
|
|
my $addr="";
|
|
|
|
my $offset="";
|
|
|
|
|
|
|
|
# get data from ntpq
|
|
|
|
open(SERVICE2, "$CMD |")
|
|
|
|
or die("Could not execute '$CMD': $!");
|
|
|
|
|
|
|
|
while(<SERVICE2>) {
|
|
|
|
if(/^srcadr=([^\s]+),\soffset=(.+)$/) {
|
|
|
|
$addr = $1;
|
|
|
|
$offset = $2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(SERVICE2);
|
|
|
|
return ($addr, $offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
# returns the offset, or U if it is undefined
|
|
|
|
sub getpeeroffset() {
|
|
|
|
my $name = shift;
|
|
|
|
my $rtn = 'U';
|
|
|
|
if (exists($peers{$name})) {
|
|
|
|
$rtn = $peers{$name};
|
|
|
|
}
|
|
|
|
return $rtn
|
|
|
|
}
|
|
|
|
|
|
|
|
=pod
|
|
|
|
|
|
|
|
=head1 Description
|
|
|
|
|
|
|
|
ntp_peers - A munin plugin to monitor offsets to multiple NTP peers and
|
|
|
|
graph them on a single graph
|
|
|
|
|
|
|
|
=head1 Parameters understood:
|
|
|
|
|
|
|
|
config (required)
|
|
|
|
autoconf (optional - used by munin-node-configure)
|
|
|
|
|
|
|
|
=head1 Configuration variables:
|
|
|
|
|
|
|
|
All configuration parameters are optional
|
|
|
|
|
|
|
|
ntpq - path to ntpq program
|
|
|
|
statedir - directory in which to place state file
|
|
|
|
hostname_<key> - override hostname for peer <key>. <key> is
|
|
|
|
an IPv4 address with dots replaced by underscores.
|
|
|
|
Useful for reference clocks, eg
|
|
|
|
env.hostname_127_127_43_0 .GPS.
|
|
|
|
|
|
|
|
=head1 Known issues
|
|
|
|
|
|
|
|
ntp_peers will not monitor IPv6 peers
|
|
|
|
|
|
|
|
=cut
|