2
0
mirror of https://github.com/munin-monitoring/contrib.git synced 2018-11-08 00:59:34 +01:00
contrib-munin/plugins/ping/ping

202 lines
6.5 KiB
Perl
Executable File

#!/usr/bin/perl -w
=cut
=head1 NAME
ping - Plugin to monitor ping times
=head1 CONFIGURATION
ping_args - Arguments to ping (default "-c 2 -w 1")
ping_args2 - Arguments after the host name (required for Solaris)
ping - Ping program to use
ping6 - Ping program to use with IPv6
hosts - List of comma-separated hosts to ping (IPv4/6 address or FQDN)
You can prepend host name with:
'A:' - to resolve all IPv4 addresses
and create an entry per address (requires 'host' program)
'AAAA:' - the same for IPv6 (requires 'host' program)
'6:' - do not try to resolve, but use ping6 for this host
names - Friendly display name of each host given in the "hosts" parameter (comma-separated list).
If not set, "hosts" elements will be used
fork - If set to non-zero, fork each ping into parallel process to ping asynchronously
Configuration example
[ping*]
env.hosts mail.example.org,6:www.example.org,AAAA:search.example.org
env.names Mail,Web,Search
env.fork yes
Configuration example for Solaris
[ping*]
env.host www.example.org mail.example.org
env.ping_args -s
env.ping_args2 56 2
You can also append '_packetloss' to the plugin filename for packet loss statistics.
=head1 AUTHOR
Original Perl script Copyright (C) 2008 Thomas Gutzler (thomas.gutzler@gmail.com)
Original Shell script Copyright (C) 2004 Jimmy Olsen
=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; version 2 dated June,
1991.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
=head1 MAGIC MARKERS
#%# family=manual
=cut
use strict;
use Munin::Plugin;
my $ping = exists $ENV{ping} ? $ENV{ping} : "ping";
my $ping6 = exists $ENV{ping6} ? $ENV{ping6} : "ping6";
# Since ping sends a packet every second (-i 1) by default,
# we may need 2 total seconds (-w 2) for <1000msec replies
my $ping_args = exists $ENV{ping_args} ? $ENV{ping_args} : "-c 2 -w 2";
my $ping_args2 = exists $ENV{ping_args2} ? $ENV{ping_args2} : "";
my $fork = exists $ENV{fork} ? $ENV{fork} : 0;
my $packetloss_mode = ($0 =~ /_packetloss$/);
my @host_options = exists $ENV{hosts} ? split(/,/, $ENV{hosts}) : "A:www.google.com";
# bare addresses
my @host_addrs = @host_options;
# ping program to use
my @host_ping = ($ping) x @host_options;
# resolve record type, if specified
my @host_resolv = (0) x @host_options;
my $config_mode = ($ARGV[0] and $ARGV[0] eq 'config');
if ($config_mode) {
print "graph_title " . ($packetloss_mode ? "Ping packet loss" : "Ping times") . "\n";
print "graph_args --base 1000 -l 0\n";
print "graph_vlabel " . ($packetloss_mode ? "%" : "seconds") . "\n";
print "graph_category network\n";
print "graph_info This graph shows ping " . ($packetloss_mode ? "packet loss" : "RTT") . " statistics.\n";
}
for (my $host_option = 0; $host_option < @host_options; ++$host_option) {
my $h_addr = $host_options[$host_option];
my @config = split(/:/, $h_addr, 2);
if ($#config) {
my $h_ping = $ping;
my $h_resolv = 0;
if ($config[0] eq "6") {
# user wants this host to be pinged via IPv6
$h_ping = $ping6;
$h_addr = $config[1];
} elsif ($config[0] eq "A") {
# user wants this host to be resolved via IPv4
$h_resolv = "A";
$h_addr = $config[1];
} elsif ($config[0] eq "AAAA") {
# user wants this host to be resolved as IPv6
$h_resolv = "AAAA";
$h_addr = $config[1];
$h_ping = $ping6;
} elsif ($config[0] =~ /^[[:xdigit:]]+$/) {
# this is IPv6 addr
$h_ping = $ping6;
} else {
# let 'host' decide what resolve type do we need
$h_resolv = $config[0];
$h_addr = $config[1];
}
$host_addrs[$host_option] = $h_addr;
$host_resolv[$host_option] = $h_resolv;
$host_ping[$host_option] = $h_ping;
}
}
# display names
my @host_names = exists $ENV{names} ? split(/,/, $ENV{names}) : @host_addrs;
if (@host_names != @host_addrs) {
print "Warning: host names specified does not match addresses\n";
}
# forked children
my @children = ();
for (my $host_i = 0; $host_i < @host_addrs; ++$host_i) {
my @h_addrs = ($host_addrs[$host_i]);
my $h_ping = $host_ping[$host_i];
my $h_resolv = $host_resolv[$host_i];
my $h_name = ($host_names[$host_i] or $h_addrs[0]);
if ($h_resolv) {
# we have to resolve the host to (probably multiple) addresses
my $h_base_addr = pop @h_addrs;
my @host = `host -t $h_resolv $h_base_addr`;
chomp @host;
for (my $h_host_i = 0; $h_host_i < @host; ++$h_host_i) {
my $h_host = $host[$h_host_i];
my ($h_addr) = $h_host =~ /address (.*)$/;
if ($h_addr) {
push @h_addrs, $h_addr;
}
}
}
for (my $h_addr_i = 0; $h_addr_i < @h_addrs; ++$h_addr_i) {
my $h_addr = $h_addrs[$h_addr_i];
my $h_cur_name = $h_resolv ? $h_name . " ($h_addr)" : $h_name;
my $h_norm_name = clean_fieldname($h_cur_name);
if ($config_mode) {
print "$h_norm_name.min 0\n$h_norm_name.label $h_cur_name\n$h_norm_name.draw LINE2\n";
my ( $warning, $critical ) =
get_thresholds($h_norm_name);
printf "%s.warning %s\n", $h_norm_name, $warning
if $warning;
printf "%s.critical %s\n", $h_norm_name, $critical
if $critical;
} else {
my $pid = $fork ? fork() : -1;
if ($pid <= 0) {
# either we can't fork, or don't want to, or we are child
my @ping = `$h_ping $ping_args $h_addr $ping_args2`;
chomp @ping;
my $ping = join(" ", @ping);
my $ping_time = "U";
my $packet_loss = "U";
$ping_time = ($1 / 1000) if ($ping =~ m@min/avg/max.*\s\d+(?:\.\d+)?/(\d+(?:\.\d+)?)/\d+(?:\.\d+)?@);
$packet_loss = $1 if ($ping =~ /(\d+)% packet loss/);
print "$h_norm_name.value ". ($packetloss_mode ? $packet_loss : $ping_time) . "\n";
if ($pid == 0) {
# this is a child process, don't forget to exit
exit(0);
}
} else {
# in parent
push @children, $pid;
}
}
}
}
for (my $child_i = 0; $child_i < @children; ++$child_i) {
waitpid($children[$child_i], 0);
}