Created
June 2, 2011 21:49
-
-
Save n8v/1005409 to your computer and use it in GitHub Desktop.
Nagios Plugin for checking Test Anything Protocol (TAP) output
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/local/bin/perl | |
### check_tap.pl | |
# By Nathan Vonnahme, n8v at users dot sourceforge dot net, June 2 2011 | |
# Allows Nagios to check the output of anything that emits Test Anything | |
# Protocol. | |
# See http://en.wikipedia.org/wiki/Test_Anything_Protocol | |
############################################################################## | |
# prologue | |
use strict; | |
use warnings; | |
use Nagios::Plugin ; | |
use TAP::Harness; | |
use vars qw($VERSION $PROGNAME $verbose $warn $critical $timeout $result); | |
$VERSION = '1.0'; | |
# get the base name of this script for use in the examples | |
use File::Basename; | |
$PROGNAME = basename($0); | |
############################################################################## | |
# define and get the command line options. | |
# see the command line option guidelines at | |
# http://nagiosplug.sourceforge.net/developer-guidelines.html#PLUGOPTIONS | |
# Instantiate Nagios::Plugin object (the 'usage' parameter is mandatory) | |
my $p = Nagios::Plugin->new( | |
usage => | |
"Usage: %s [ -v|--verbose ] [-t <timeout>] | |
[ -c|--critical=<critical threshold> ] | |
[ -w|--warning=<warning threshold> ] | |
[ -s|--script = '</full/path/to/test.t>' ] (Required. multiple OK) | |
[ -e|--exec = '/full/path/to/runnable ARGS' | |
[ -l|--lib = '/path/to/perl/libs' ] (Multiple OK) | |
", | |
version => $VERSION, | |
blurb => | |
"This plugin allows Nagios to check the output of anything that emits | |
Test Anything Protocol output. So you can wed Nagios's monitoring and | |
alerting infrastructure to your unit and functional tests for deep | |
application-level monitoring in development or even in production.", | |
extra => qq{ | |
## Verbosity | |
Use -v to see a bit more info in the one line, including the first | |
test that failed. This is especially useful because Nagios will | |
include it in the alert/notification. | |
Use -vv to see test summary and failures. | |
Use -vvv to see full test script output. | |
## Warning and Critical Thresholds | |
THRESHOLDs for -w and -c specify the allowable amount of test failures | |
before the plugin returns WARNING or CRITICAL. Use 'max' or 'min:max'. | |
The default of 0 tolerated failures is good for people like you who | |
have high standards. But you might want to crank up the CRITICAL | |
threshold if you want to differentiate between WARNING and CRITICAL | |
amounts of fail. | |
See more threshold examples at | |
http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT | |
## Examples: | |
$PROGNAME -s /full/path/to/testfoo.pl | |
will run 'testfoo.pl' and return OK if 0 tests fail, but CRITICAL if | |
any fail. Excluding TODO or SKIPped tests, of course. | |
$PROGNAME -s /full/path/to/testfoo.pl -c 2 | |
will return OK if 0 tests fail, WARNING if more than 0 tests fail, | |
but CRITICAL if more than 2 fail. | |
$PROGNAME -s /full/path/to/testfoo.pl -w 2 c 4 | |
will return OK if 0 tests fail, WARNING if more than 2 tests fail, | |
and CRITICAL if more than 4 fail. | |
## Non-Perl and remote test scripts | |
$PROGNAME -e '/usr/bin/ruby -w' -s /full/path/to/testfoo.r | |
will run 'testfoo.r' using Ruby with the -w flag. | |
You can use any shell command and argument which produces TAP output, | |
for example: | |
$PROGNAME -e '/usr/bin/curl -sk' -s 'http://url/to/mytest.php' | |
$PROGNAME -e '/usr/bin/cat' -s '/path/to/testoutput.tap' | |
In fact, anything TAP::Harness or `prove` regards as a source or | |
executable. | |
Remember that Nagios or NRPE will likely be running this command as a | |
different, less-privileged user than you're using now. | |
} | |
); | |
# Define and document the valid command line options | |
# usage, help, version, timeout and verbose are defined by default. | |
$p->add_arg( | |
spec => 'script|s=s@', | |
required => 1, | |
help => | |
qq{-s, --script="/path/to/executable/test.t args" | |
REQUIRED. Defines the path to the test script you want to run. | |
Use multiple -s flags to run multiple tests. | |
} | |
); | |
$p->add_arg( | |
spec => 'lib|l=s@', | |
help => | |
qq{-l, --lib="/path/to/perl/lib/dir" | |
Optional path for Perl libs to add to \@INC. | |
Use multiple -l flags to specify multiple lib dirs. | |
} | |
); | |
$p->add_arg( | |
spec => 'exec|e=s', | |
required => 0, | |
help => | |
qq{-e, --exec="/path/to/executable args" | |
Defines a non-Perl executable with which you want to run the --script. | |
} | |
); | |
$p->add_arg( | |
spec => 'warning|w=s', | |
default => 0, | |
help => | |
qq{-w, --warning=INTEGER:INTEGER | |
Minimum and maximum number of allowable test FAILURES, outside of which a | |
warning will be generated. Default is 0 tolerable failures. | |
}, | |
); | |
$p->add_arg( | |
spec => 'critical|c=s', | |
default => 0, | |
help => | |
qq{-c, --critical=INTEGER:INTEGER | |
Minimum and maximum number of allowable test FAILURES, outside of | |
which a critical will be generated. Default is 0 tolerable failures. | |
}, | |
); | |
# Parse arguments and process standard ones (e.g. usage, help, version) | |
$p->getopts; | |
############################################################################## | |
# Do it, and do it, and do it. | |
my $message = ""; | |
alarm($p->opts->timeout); | |
# Capture STDOUT/STDERR to emit if verbose | |
my $raw_test_output = ""; | |
# opens a virtual filehandle that will write to $raw_test_output | |
open(my $fh, '>', \$raw_test_output); | |
# -v and -vv need Harness verbosity = 0 | |
# -vvv+ need verbosity = 1 | |
my $harness = TAP::Harness->new( { | |
verbosity => ($p->opts->verbose >=3), | |
failures => 1, | |
merge => 1, | |
errors => 1, | |
stdout => $fh, | |
formatter_class => 'TAP::Formatter::File', | |
ignore_exit => 1, | |
lib => $p->opts->lib, | |
} ); | |
if ($p->opts->exec) { | |
# exec => [split /\s+/, $p->opts->exec]; | |
$harness->exec([split /\s+/, $p->opts->exec]); | |
} | |
my $aggregator = $harness->runtests( @{$p->opts->script} ); | |
alarm(0); | |
my $result = $aggregator->failed; | |
$p->add_perfdata( | |
label => "total", | |
value => $aggregator->total, | |
); | |
$p->add_perfdata( | |
label => "failures", | |
value => $result, | |
threshold => $p->threshold, | |
); | |
$p->add_perfdata( | |
label => "passed", | |
value => scalar $aggregator->passed, | |
); | |
if ( $aggregator->exit >= 255 ) { | |
$message = sprintf("Test script failed to exit normally after %d tests (%d failures)", | |
scalar $aggregator->total, scalar $aggregator->failed); | |
$message .= "\n$raw_test_output" if $p->opts->verbose > 0; | |
$p->nagios_exit( | |
return_code => CRITICAL, | |
message => $message | |
); | |
} | |
$message = $aggregator->get_status; | |
if ($p->opts->verbose > 0) { | |
my $first_failure = ""; | |
if ($aggregator->failed && $raw_test_output =~ /^not ok.*$/m) { | |
$first_failure = " 1st='$&'"; | |
} | |
$message .= sprintf(". %d of %d failed. %s%s", | |
scalar $aggregator->failed, | |
scalar $aggregator->total, | |
($p->opts->warning || $p->opts->critical ? | |
sprintf "Warning/critical at %d/%d.", | |
$p->opts->warning, | |
$p->opts->critical : | |
""), | |
$first_failure | |
); | |
$message .= "\n" . $raw_test_output | |
if $p->opts->verbose > 1; | |
} | |
############################################################################## | |
# check the result against the defined warning and critical thresholds, | |
# output the result and exit | |
$p->nagios_exit( | |
return_code => $p->check_threshold($result), | |
message => $message | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See my blog post about this plugin for more information.