ntp_
Name
ntp_ - Wildcard plugin to monitor NTP statistics for a particular remote NTP peer
Configuration
This is a wildcard plugin. The wildcard suffix in the symlink is the
hostname, IPv4, or IPv6 address of the NTP peer that you want to
monitor. The IP address must be one which appears in ntpq -np
output. If given a hostname, it must resolve to an IP address which
appears in ntpq -np
output; this plugin will try all of the A or
AAAA records returned. If you use a dynamic association method, such
as “pool” or one of the broadcast or multicast methods, this plugin
will probably not work very well for you, as your NTP peers could be
changing frequently.
Examples:
- ntp_time.example.com
- ntp_203.0.113.1
- ntp_2001:db8::1
The following environment variables are used by this plugin:
[ntp_*]
env.lowercase - Lowercase hostnames after lookup
env.nodelay 1 - Set to 1 to disable graphing of delay
Author
Original author unknown. Rewritten by Kenyon Ralph kenyon@kenyonralph.com.
License
Same as munin.
Magic Markers
#%# family=auto
#%# capabilities=autoconf suggest
#!@@PERL@@ -w
# -*- mode: cperl; cperl-indent-level: 8; -*-
=head1 NAME
ntp_ - Wildcard plugin to monitor NTP statistics for a particular remote NTP peer
=head1 CONFIGURATION
This is a wildcard plugin. The wildcard suffix in the symlink is the
hostname, IPv4, or IPv6 address of the NTP peer that you want to
monitor. The IP address must be one which appears in C<ntpq -np>
output. If given a hostname, it must resolve to an IP address which
appears in C<ntpq -np> output; this plugin will try all of the A or
AAAA records returned. If you use a dynamic association method, such
as "pool" or one of the broadcast or multicast methods, this plugin
will probably not work very well for you, as your NTP peers could be
changing frequently.
Examples:
=over
=item ntp_time.example.com
=item ntp_203.0.113.1
=item ntp_2001:db8::1
=back
The following environment variables are used by this plugin:
[ntp_*]
env.lowercase - Lowercase hostnames after lookup
env.nodelay 1 - Set to 1 to disable graphing of delay
=head1 AUTHOR
Original author unknown. Rewritten by Kenyon Ralph <kenyon@kenyonralph.com>.
=head1 LICENSE
Same as munin.
=head1 MAGIC MARKERS
#%# family=auto
#%# capabilities=autoconf suggest
=cut
use English qw( -no_match_vars );
use strict;
use warnings;
# work around "strict" check for this variable exported by "Net::IP"
my $ip_identical;
eval {
no warnings "once";
require Net::DNS;
Net::DNS->import();
require Net::IP;
Net::IP->import();
$ip_identical = $Net::IP::IP_IDENTICAL;
};
my $has_requirements = $EVAL_ERROR ? 0 : 1;
if ($ARGV[0] and $ARGV[0] eq "autoconf") {
if (!$has_requirements) {
print "no (missing Net::DNS or Net::IP modules)\n";
} else {
`ntpq -c help >/dev/null 2>/dev/null`;
if ($CHILD_ERROR eq "0") {
if (`ntpq -n -c peers | wc -l` > 0) {
print "yes\n";
} else {
print "no (ntpq -p returned no peers)\n";
}
} else {
print "no (ntpq not found)\n";
}
}
exit 0;
}
if ($ARGV[0] and $ARGV[0] eq "suggest") {
foreach my $line (`ntpq -c associations`) {
if ($line =~ m/^\s*\d+/) {
my (undef, undef, $assid, undef, undef, undef, undef, undef, undef, undef) = split(/\s+/, $line);
chomp(my $peerinfo = `ntpq -n -c "readvar $assid srcadr"`);
$peerinfo =~ s/\R/ /g;
my ($peer_addr) = ($peerinfo =~ m/srcadr=(.*)/);
print $peer_addr, "\n" unless $peer_addr eq "0.0.0.0";
}
}
exit 0;
}
my $nodelay = $ENV{'nodelay'} || 0;
$0 =~ /ntp_(.+)*$/;
my $name = $1;
die "No hostname or IP address provided" unless defined $name;
if ($ARGV[0] and $ARGV[0] eq "config") {
print "graph_title NTP statistics for peer $name\n";
print "graph_args --base 1000 --vertical-label seconds --lower-limit 0\n";
print "graph_category time\n";
print "delay.label Delay\n";
print "delay.graph no\n" if $nodelay;
print "delay.cdef delay,1000,/\n";
print "offset.label Offset\n";
print "offset.cdef offset,1000,/\n";
print "jitter.label Jitter\n";
print "jitter.cdef jitter,1000,/\n";
exit 0;
}
my $srcadr = "";
my $delay = "U";
my $offset = "U";
my $jitter = "U";
my @associations = `ntpq -c associations`;
foreach my $line (@associations) {
if ($line =~ m/^\s*\d+/) {
my (undef, undef, $assid, undef, undef, undef, undef, undef, undef, undef) = split(/\s+/, $line);
chomp(my $peerinfo = `ntpq -n -c "readvar $assid srcadr,delay,offset,jitter"`);
$peerinfo =~ s/\R/ /g;
($srcadr) = ($peerinfo =~ m/srcadr=([^, ]+)/);
($delay) = ($peerinfo =~ m/delay=([^, ]+)/);
($offset) = ($peerinfo =~ m/offset=([^, ]+)/);
($jitter) = ($peerinfo =~ m/jitter=([^, ]+)/);
last if lc($srcadr) eq lc($name);
}
}
my $matched = 0;
if (lc($srcadr) ne lc($name)) {
my @addresses;
my $resolver = Net::DNS::Resolver->new;
$resolver->tcp_timeout(5);
$resolver->udp_timeout(5);
my $query = $resolver->search($name, "AAAA");
if ($query) {
foreach my $rr ($query->answer) {
if ("AAAA" eq $rr->type) {
push(@addresses, new Net::IP($rr->address));
}
}
}
$query = $resolver->search($name, "A");
if ($query) {
foreach my $rr ($query->answer) {
if ("A" eq $rr->type) {
push(@addresses, new Net::IP($rr->address));
}
}
}
ASSOCS: foreach my $line (@associations) {
if ($line =~ m/^\s*\d+/) {
my (undef, undef, $assid, undef, undef, undef, undef, undef, undef, undef) = split(/\s+/, $line);
chomp(my $peerinfo = `ntpq -n -c "readvar $assid srcadr,delay,offset,jitter"`);
$peerinfo =~ s/\R/ /g;
($srcadr) = ($peerinfo =~ m/srcadr=([^, ]+)/);
($delay) = ($peerinfo =~ m/delay=([^, ]+)/);
($offset) = ($peerinfo =~ m/offset=([^, ]+)/);
($jitter) = ($peerinfo =~ m/jitter=([^, ]+)/);
($srcadr) = new Net::IP($srcadr);
ADDRS: foreach my $addr (@addresses) {
if (defined($srcadr->overlaps($addr)) and $srcadr->overlaps($addr) == $ip_identical) {
$matched = 1;
last ASSOCS;
}
}
}
}
}
if (lc($srcadr) ne lc($name) and $matched == 0) {
die "$name is not a peer of this ntpd";
}
print <<"EOT";
delay.value $delay
offset.value $offset
jitter.value $jitter
EOT
exit 0;
# vim:syntax=perl