Projet

Général

Profil

Révision dca361d0

IDdca361d029727d22052708ec05bc166644b832b9
Parent 8d941d04
Enfant ec431eb3

Ajouté par Artem Sheremet il y a plus de 13 ans

Rewriting Ping plugin in perl

  • Merging existing plugins

Voir les différences:

plugins/network/ping/ping
1
#!/bin/bash
2

  
3
# ping revision 2 (Jul 2012)
4
#
5
# This plugin shows ping statistics for several hosts on a single graph
6
#
7
# Configuration:
8
#   Add [ping] section with 'hosts' set to space-separated list of hostnames or addresses.
9
#   You can prefix host name with '<type>:' to change IP resolution mode,
10
#   e.g. 'AAAA:domain.tld' will request IPv6 record.
11
#   Always prefix IPv6 addresses with 'AAAA:' (internal limitation).
12
#
13
# Dependencies:
14
# 	host util is required
15
#
16
# OS:
17
# 	Linux
18
#
19
# Author: Artem Sheremet <dot.doom@gmail.com>
20
#
21

  
22
function normalize() {
23
	echo ${1//[^a-zA-Z0-9]/_}
24
}
1
#!/usr/bin/perl -w
2

  
3
=cut
4

  
5
=head1 NAME
6

  
7
ping - Plugin to monitor ping times
8

  
9
=head1 CONFIGURATION
10

  
11
 ping_args      - Arguments to ping (default "-c 2 -w 1")
12
 ping_args2     - Arguments after the host name (required for Solaris)
13
 ping           - Ping program to use
14
 ping6          - Ping program to use with IPv6
15
 hosts          - List of comma-separated hosts to ping (IPv4/6 address or FQDN)
16
                  You can prepend host name with:
17
                  'A:'    - to resolve all IPv4 addresses
18
                            and create an entry per address (requires 'host' program)
19
                  'AAAA:' - the same for IPv6 (requires 'host' program)
20
                  '6:'    - do not try to resolve, but use ping6 for this host
21
 names          - Friendly display name of each host given in the "hosts" parameter (comma-separated list).
22
                  If not set, "hosts" elements will be used
23
 fork           - If set to non-zero, fork each ping into parallel process to ping asynchronously
24

  
25
Configuration example
26

  
27
 [ping]
28
 env.hosts mail.example.org,6:www.example.org,AAAA:search.example.org
29
 env.names Mail,Web,Search
30
 env.fork yes
31

  
32
Configuration example for Solaris
33

  
34
 [multiping]
35
 env.host www.example.org mail.example.org
36
 env.ping_args -s
37
 env.ping_args2 56 2
38

  
39
You can also append plugin name with '_packetloss' to get packet loss statistics.
40

  
41
=head1 AUTHOR
42

  
43
Original Perl script Copyright (C) 2008 Thomas Gutzler (thomas.gutzler@gmail.com)
44
Original Shell script Copyright (C) 2004 Jimmy Olsen
45

  
46
=head1 LICENSE
47

  
48
This program is free software; you can redistribute it and/or
49
modify it under the terms of the GNU General Public License
50
as published by the Free Software Foundation; version 2 dated June,
51
1991.
52

  
53
This program is distributed in the hope that it will be useful,
54
but WITHOUT ANY WARRANTY; without even the implied warranty of
55
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
56
GNU General Public License for more details.
57

  
58
You should have received a copy of the GNU General Public License
59
along with this program; if not, write to the Free Software
60
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 61

  
26
function host_type() {
27
	case $1 in
28
		*:*)
29
			echo ${1/:*/}
30
			;;
31
		*)
32
			echo A
33
			;;
34
	esac
62
=head1 MAGIC MARKERS
63

  
64
#%# family=manual
65

  
66
=cut
67

  
68
use strict;
69
use Munin::Plugin;
70

  
71
my $ping = exists $ENV{ping} ? $ENV{ping} : "ping";
72
my $ping6 = exists $ENV{ping6} ? $ENV{ping6} : "ping6";
73
my $ping_args = exists $ENV{ping_args} ? $ENV{ping_args} : "-c 2 -w 1";
74
my $ping_args2 = exists $ENV{ping_args2} ? $ENV{ping_args2} : "";
75
my $fork = exists $ENV{fork} ? $ENV{fork} : 0;
76
my $packetloss_mode = ($0 =~ /_packetloss$/);
77

  
78
my @host_options = exists $ENV{hosts} ? split(/,/, $ENV{hosts}) : "A:www.google.com";
79

  
80
# bare addresses
81
my @host_addrs = @host_options;
82

  
83
# ping program to use
84
my @host_ping = ($ping) x @host_options;
85

  
86
# resolve record type, if specified
87
my @host_resolv = (0) x @host_options;
88

  
89
my $config_mode = ($ARGV[0] and $ARGV[0] eq 'config');
90
if ($config_mode) {
91
	print "graph_title " . ($packetloss_mode ? "Ping packet loss" : "Ping times") . "\n";
92
	print "graph_args --base 1000 -l 0\n";
93
	print "graph_vlabel " . ($packetloss_mode ? "packets" : "seconds") . "\n";
94
	print "graph_category network\n";
95
	print "graph_info This graph shows ping " . ($packetloss_mode ? "packet loss" : "RTT") . " statistics.\n";
35 96
}
36 97

  
37
function host_name() {
38
	echo "${1/*:/}"
98
for (my $host_option = 0; $host_option < @host_options; ++$host_option) {
99
	my $h_addr = $host_options[$host_option];
100
	my @config = split(/:/, $h_addr, 2);
101
	if ($#config) {
102
		my $h_ping = $ping;
103
		my $h_resolv = 0;
104
		if ($config[0] eq "6") {
105
			# user wants this host to be pinged via IPv6
106
			$h_ping = $ping6;
107
			$h_addr = $config[1];
108
		} elsif ($config[0] eq "A") {
109
			# user wants this host to be resolved via IPv4
110
			$h_resolv = "A";
111
			$h_addr = $config[1];
112
		} elsif ($config[0] eq "AAAA") {
113
			# user wants this host to be resolved as IPv6
114
			$h_resolv = "AAAA";
115
			$h_addr = $config[1];
116
			$h_ping = $ping6;
117
		} elsif ($config[0] =~ /^[[:xdigit:]]+$/) {
118
			# this is IPv6 addr
119
			$h_ping = $ping6;
120
		} else {
121
			# let 'host' decide what resolve type do we need
122
			$h_resolv = $config[0];
123
			$h_addr = $config[1];
124
		}
125
		$host_addrs[$host_option] = $h_addr;
126
		$host_resolv[$host_option] = $h_resolv;
127
		$host_ping[$host_option] = $h_ping;
128
	}
39 129
}
40 130

  
41
function ipof() {
42
	host -t $(host_type $1) $(host_name $1) |
43
		sort | grep -Eo 'address .*' | cut -d' ' -f2 | head -1
131
# display names
132
my @host_names = exists $ENV{names} ? split(/,/, $ENV{names}) : @host_addrs;
133

  
134
if (@host_names != @host_addrs) {
135
	print "Warning: host names specified does not match addresses\n";
44 136
}
45 137

  
46
if [[ "$1" == "config" ]]; then
47
	echo 'graph_title Ping statistics
48
graph_vlabel Time,ms
49
graph_category network
50
graph_info ping statistics for several hosts'
51
	for host in $hosts; do
52
		echo "$(normalize $host).label $(host_name $host) ($(ipof $host))"
53
	done
54
	exit 0
55
fi
56

  
57
SYNC_FILE=/tmp/munin-ping-sync
58
echo -n >"$SYNC_FILE"
59

  
60
COUNT=0
61
for host in $hosts; do
62
	{
63
		case $(host_type $host) in
64
			AAAA)
65
				PING=ping6
66
				;;
67
			*)
68
				PING=ping
69
				;;
70
		esac
71
		TIME=$($PING -w 1 -c 1 `host_name $host` | awk '
72
			BEGIN {
73
				found = 0
74
				t = 0
75
			}
138
# forked children
139
my @children = ();
140

  
141
for (my $host_i = 0; $host_i < @host_addrs; ++$host_i) {
142
	my @h_addrs = ($host_addrs[$host_i]);
143
	my $h_ping = $host_ping[$host_i];
144
	my $h_resolv = $host_resolv[$host_i];
145
	my $h_name = $host_names[$host_i];
76 146

  
77
			$1 == "rtt" { found = 1; t = $4; }
147
	if ($h_resolv) {
148
		# we have to resolve the host to (probably multiple) addresses
149
		my $h_base_addr = pop @h_addrs;
150
		my @host = `host -t $h_resolv $h_base_addr`;
151
		chomp @host;
152
		for (my $h_host_i = 0; $h_host_i < @host; ++$h_host_i) {
153
			my $h_host = $host[$h_host_i];
154
			my ($h_addr) = $h_host =~ /address (.*)$/;
155
			if ($h_addr) {
156
				push @h_addrs, $h_addr;
157
			}
158
		}
159
	}
78 160

  
79
			END {
80
				if (found == 1) {
81
					split(t, parts, "/");
82
					print parts[1]
83
				} else {
84
					print "U"
161
	for (my $h_addr_i = 0; $h_addr_i < @h_addrs; ++$h_addr_i) {
162
		my $h_addr = $h_addrs[$h_addr_i];
163
		my $h_cur_name = $h_resolv ? $h_name . " ($h_addr)" : $h_name;
164
		my $h_norm_name = clean_fieldname($h_cur_name);
165
		if ($config_mode) {
166
			print "$h_norm_name.min 0\n$h_norm_name.label $h_cur_name\n$h_norm_name.draw LINE2\n";
167
		} else {
168
			my $pid = $fork ? fork() : -1;
169
			if ($pid <= 0) {
170
				# either we can't fork, or don't want to, or we are child
171
				my @ping = `$h_ping $ping_args $h_addr $ping_args2`;
172
				chomp @ping;
173
				my $ping = join(" ", @ping);
174
				my $ping_time = ($1 / 1000) if ($ping =~ m@min/avg/max.*\s\d+(?:\.\d+)?/(\d+(?:\.\d+)?)/\d+(?:\.\d+)?@);
175
				my $packet_loss = $1 if ($ping =~ /(\d+)% packet loss/);
176
				print "$h_norm_name.value ". ($packetloss_mode ? $packet_loss : $ping_time) . "\n";
177
				if ($pid == 0) {
178
					# this is a child process, don't forget to exit
179
					exit(0);
85 180
				}
181
			} else {
182
				# in parent
183
				push @children, $pid;
86 184
			}
87
		')
88

  
89
		echo $(normalize $host).value $TIME
90
		echo ok >>"$SYNC_FILE"
91
	} &
92
	let COUNT=$COUNT+1
93
done
94

  
95
# wait for background processes to finish
96
while [ $(wc -l <"$SYNC_FILE") -lt $COUNT ]; do
97
	sleep 0.2
98
done
185
		}
186
	}
187
}
188

  
189
for (my $child_i = 0; $child_i < @children; ++$child_i) {
190
	waitpid($children[$child_i], 0);
191
}

Formats disponibles : Unified diff