Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
check_munin.pl に http://goo.gl/KpjnAhttp://goo.gl/9O0ii の対応を盛り込んだ。ver 0.9.1
#!/usr/bin/perl -w
# $Id: check_munin.pl
# 2011/10/03 17:34:54
#
# check_munin.pl Copyright (C) 2003 Julien Rottenberg <julien@rottenberg.info>
#
# check_munin.pl can check various modules of a server running munin-node.
#
#
# 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 (or with Nagios); if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA
# Globals
our $PROGNAME = "check_munin.pl";
my $host = undef; # hostname
my $port = 4949; # port
my $module = undef; # module to load
my $timeout = 5; # basic timeout
my @check_values = ();
my $DEBUG = 0;
my $REVISION = "0.9.1";
use strict;
use Getopt::Long;
use vars qw($opt_V $opt_h $opt_w $opt_c $opt_H $opt_P $opt_M $PROGNAME);
#use lib "/usr/lib/nagios/plugins" ;
#use lib "./" ;
use lib "/usr/local/nagios/libexec" ;
use utils qw(%ERRORS &print_revision &support &usage);
use IO::Socket::INET;
$ENV{'PATH'}='';
$ENV{'BASH_ENV'}='';
$ENV{'ENV'}='';
Getopt::Long::Configure('bundling');
GetOptions(
"V" => \$opt_V, "version" => \$opt_V,
"h" => \$opt_h, "help" => \$opt_h,
"w=s" => \$opt_w, "warning=s" => \$opt_w,
"c=s" => \$opt_c, "critical=s" => \$opt_c,
"H=s" => \$opt_H, "hostname=s" => \$opt_H,
"P=s" => \$opt_P, "port=s" => \$opt_P,
"M=s" => \$opt_M, "module=s" => \$opt_M
);
##
##
## Functions
##
##
sub check_options {
# Basic checks
if ($opt_V) {
print_revision($PROGNAME,'$Revision: '.$REVISION.' $');
exit $ERRORS{'UNKNOWN'};
}
if ($opt_h) {
print_help ();
print_revision($PROGNAME,'$Revision: '.$REVISION. ' $');
exit $ERRORS{'UNKNOWN'};
}
# Check Hostname and module
if (!defined($opt_H) || !defined($opt_M)) {
print "Hostname and module are requested !\n";
print_usage();
exit $ERRORS{"UNKNOWN"}
} else {
$host = $opt_H if (utils::is_hostname($opt_H));
($host) || usage("Invalid hostname or address : $opt_H\n");
my @modules = split(':', $opt_M);
$module = shift(@modules);
if (scalar(@modules)) {
@check_values = @modules;
} else {
undef(@check_values);
}
}
# Check warnings and critical
if (!defined($opt_w) || !defined($opt_c)) {
print "put warning and critical info !\n";
print_usage();
exit $ERRORS{"UNKNOWN"}
}
# Check Port number
if (defined($opt_P)) {
if ($opt_P !~ m/^[0-9]*$/) {
print "Port must be a number ! (4949 is the default)\n";
print_usage();
exit $ERRORS{"UNKNOWN"}
} else {
$port = $opt_P;
}
}
}
sub print_usage () {
print "Usage: $0 -H <host> -M <Module>[:<Field>] [-P <port>] -w <warn level> -c <crit level> [-V]\n";
}
sub print_help () {
print "\nMonitor remote server via Munin-node agent\n";
print_usage();
print <<EOT;
-h, --help
print this help message
-H, --hostname=HOST
name or IP address of host to check
-M, --module=MUNIN MODULE ex) "Module[:Field]"
Munin module value to fetch
-P, --port=PORT
Munin-node port (Default 4949)
-w, --warn=INTEGER
warning level
-c, --crit=INTEGER
critical level
-t, --timeout=INTEGER
timeout for Munin-node connection in seconds (Default: 5)
-V, --version
prints version number
EOT
}
sub in ($$);
$ENV{'BASH_ENV'}='';
$ENV{'ENV'}='';
$ENV{'PATH'}='';
$ENV{'LC_ALL'}='C';
##
##
## Let's go !
##
##
# check if everything is ok
check_options();
# Connect to host
my ($munin,$error);
my %data;
my $status = "0"; # status is ok by default, 1 = warning, 2 = critical
my ($object_name, $object_value, $object_threshold);
my $response_text = '';
$munin = IO::Socket::INET->new("PeerAddr" => $host, "PeerPort" => $port, "Timeout" => $timeout);
if (!defined($munin)) {
printf("ERROR opening session on munin-node, try yourself : telnet $host $port\n", $error);
exit $ERRORS{"UNKNOWN"};
}
$munin->autoflush(1); # This is the default but for version >= 1.18
# Call the module to load
print $munin "fetch $module\n";
# get data and parse it
# all munin plugins call have to
# - start with a prompt : # munin node at $hostname
# - end with a line only containg a dot
my $line = "";
while ($line !~ m/^\./) {
$line = $munin -> getline();
print $line if $DEBUG;
if (($line !~ /^\#\ munin\ node\ at\ /) && ($line !~ /^\.$/)) { # Get rid of the first line : "# munin node at HOSTNAME" and of the last one (.)
my @couple = split(' ', $line);
$couple[0] = sanitize($couple[0]); # Let's have a nicer output
print "$couple[0]\n" if $DEBUG; # Some lines from Munin are not useful var_run for module df for example
if ($couple[0]) {
$couple[0] =~ s/\.value//; # We don't need that part anyway
$data{$couple[0]} = $couple[1];
print "|$couple[0] - $couple[1]|\n" if $DEBUG;
}
}
}
# if module does not exist munin-node reports : # Unknown service
if (($data{'#'}) && ($data{'#'} eq 'Unknown')) {
print "ERROR No such module : $module on munin-node $host.\n";
exit $ERRORS{"UNKNOWN"};
}
print $munin "quit\n"; # Let's get out of here
close $munin; # Close the connection nicely
# check data
# Structure %data : name ==> value
my $threshold_status;
foreach my $name (keys %data) {
my $value = $data{$name};
print "$name $value\n" if $DEBUG;
undef($threshold_status);
if (scalar(@check_values)) {
unless (scalar(grep(/$name/, @check_values))) {
next;
}
}
$threshold_status = check_threshold($value, $opt_w);
if ($threshold_status && ($status ne 2)) {
$status = "1";
$object_name = $name;
$object_value = $value;
$object_threshold = $threshold_status;
}
$threshold_status = check_threshold($value, $opt_c);
if ($threshold_status) {
$status = "2";
$object_name = $name;
$object_value = $value;
$object_threshold = $threshold_status;
}
$response_text = $name.": ".$value." ".$response_text ; # this one will print all objects munin see
print "$response_text\n" if $DEBUG;
}
if ($status eq 1) {
print "$object_name value, $object_value, is $object_threshold warning threshold $opt_w\n";
$status = $ERRORS{"WARNING"};
} elsif ($status eq 2) {
print "$object_name value, $object_value, is $object_threshold critical threshold $opt_c\n";
$status = $ERRORS{"CRITICAL"};
} else {
print "$response_text\n";
$status = $ERRORS{"OK"};
}
exit $status;
##
##
## Functions
##
##
sub check_threshold {
my $check = shift;
my $opt = shift;
my $pattern_num = '(?:[-+]?\d+(?:\.\d+)?(?:[eE][-+]?\d+)?)';
my $pattern_check = "^(${pattern_num}+)\$|^(@)*((?:${pattern_num}|~)*):(${pattern_num}*)\$";
my $range = undef;
my $min = undef;
my $max = undef;
if ($opt =~ /^${pattern_check}/) {
$range = $2 ? "inside" : "outside";
$min = $1 ? 0 : ($3 && ($3 eq "~")) ? undef : $3 ;
$max = $1 ? $1 : $4 ;
}
print("\[${range}\] ${min} - ${max} | (${check})\n") if ($DEBUG);
undef($min) if ($min eq "");
undef($max) if ($max eq "");
if (defined($min) && defined($max)) {
($min, $max) = ($max, $min) if ($min > $max);
}
if ($range eq "outside") {
if ((defined($min) && defined($max)) && ($check < $min || $check > $max)) {
return ($check < $min) ? "below" : "above" ;
} elsif ((defined($min) && !defined($max)) && $check < $min) {
return "below";
} elsif ((!defined($min) && defined($max)) && $check > $max) {
return "above";
} else {
return 0;
}
} elsif ($range eq "inside") {
if ((defined($min) && defined($max)) && $check >= $min && $check <= $max) {
return "between";
} else {
return 0;
}
}
return undef;
}
sub sanitize {
my $var = shift;
if ($opt_M eq "df") {
# Get rid of non physical drives
if (($var !~ m/dev/ ) || ($var =~ m/udev/) || ($var =~ m/shm/)) {
$var = undef;
} else {
$var =~ s/\_/\//g;
}
}
return $var;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment