Monitoring-Plugin-0.40/0000755000175000017500000000000013326155245013534 5ustar svensvenMonitoring-Plugin-0.40/t/0000755000175000017500000000000013326155245013777 5ustar svensvenMonitoring-Plugin-0.40/t/npg03/0000755000175000017500000000000013326155245014726 5ustar svensvenMonitoring-Plugin-0.40/t/npg03/input/0000755000175000017500000000000013326155245016065 5ustar svensvenMonitoring-Plugin-0.40/t/npg03/input/05_disk60000644000175000017500000000010212267046307017326 0ustar svensvencheck_disk2 --warning=10% --critical=5% --extra-opts= --path=/usr Monitoring-Plugin-0.40/t/npg03/input/05_disk10000644000175000017500000000004212267046307017324 0ustar svensvencheck_disk --extra-opts= -p /home Monitoring-Plugin-0.40/t/npg03/input/05_disk20000644000175000017500000000005412267046307017330 0ustar svensvencheck_disk --extra-opts= -p /home -p /users Monitoring-Plugin-0.40/t/npg03/input/14_badsection_dies0000644000175000017500000000005212267046307021431 0ustar svensvencheck_no_section --extra-opts=bad_section Monitoring-Plugin-0.40/t/npg03/input/00_basic0000644000175000017500000000010412267046307017364 0ustar svensvencheck_mysql -S --extra-opts= --extra-opts=more_options -H localhost Monitoring-Plugin-0.40/t/npg03/input/02_override20000644000175000017500000000004312267046307020210 0ustar svensvencheck_mysql --extra-opts= -u admin Monitoring-Plugin-0.40/t/npg03/input/13_nosection_explicit_dies0000644000175000017500000000005412267046307023221 0ustar svensvencheck_no_section --extra-opts= -H localhost Monitoring-Plugin-0.40/t/npg03/input/00_noextra0000644000175000017500000000003412267046307017765 0ustar svensvencheck_mysql -S -H localhost Monitoring-Plugin-0.40/t/npg03/input/15_badsection_catch0000644000175000017500000000006712267046307021576 0ustar svensvencheck_no_section_default_file --extra-opts=bad_section Monitoring-Plugin-0.40/t/npg03/input/12_nosection_implicit0000644000175000017500000000003612267046307022205 0ustar svensvencheck_no_section -H localhost Monitoring-Plugin-0.40/t/npg03/input/05_disk70000644000175000017500000000004612267046307017336 0ustar svensvencheck_disk3 --extra-opts --path=/home Monitoring-Plugin-0.40/t/npg03/input/05_disk30000644000175000017500000000004612267046307017332 0ustar svensvencheck_disk --extra-opts=check_2_disks Monitoring-Plugin-0.40/t/npg03/input/01_override10000644000175000017500000000010312267046307020203 0ustar svensvencheck_mysql --username=admin --extra-opts=more_options --warning=5 Monitoring-Plugin-0.40/t/npg03/input/05_disk40000644000175000017500000000005712267046307017335 0ustar svensvencheck_disk -p /home --extra-opts=check_2_disks Monitoring-Plugin-0.40/t/npg03/input/05_disk50000644000175000017500000000006712267046307017337 0ustar svensvencheck_disk -p /home --extra-opts=check_2_disks_reprise Monitoring-Plugin-0.40/t/npg03/input/09_funnystuff0000644000175000017500000000004412267046307020526 0ustar svensvencheck_disk --extra-opts=funny_stuff Monitoring-Plugin-0.40/t/npg03/expected/0000755000175000017500000000000013326155245016527 5ustar svensvenMonitoring-Plugin-0.40/t/npg03/expected/05_disk20000644000175000017500000000004612267046307017773 0ustar svensvencheck_disk -p /tmp -p /home -p /users Monitoring-Plugin-0.40/t/npg03/expected/05_disk70000644000175000017500000000005612267046307020001 0ustar svensvencheck_disk3 -p / -p /var -p /tmp --path=/home Monitoring-Plugin-0.40/t/npg03/expected/15_badsection_catch0000644000175000017500000000010312267046307022227 0ustar svensvenInvalid section 'bad_section' in config file 't/npg03/plugins.ini' Monitoring-Plugin-0.40/t/npg03/expected/05_disk30000644000175000017500000000003312267046307017770 0ustar svensvencheck_disk -p /tmp -p /var Monitoring-Plugin-0.40/t/npg03/expected/00_noextra0000644000175000017500000000003412267046307020427 0ustar svensvencheck_mysql -H localhost -S Monitoring-Plugin-0.40/t/npg03/expected/01_override10000644000175000017500000000007012267046307020650 0ustar svensvencheck_mysql --critical=15 --username=admin --warning=5 Monitoring-Plugin-0.40/t/npg03/expected/05_disk60000644000175000017500000000013012267046307017771 0ustar svensvencheck_disk2 --critical=5% --path=/var --path=/home --path=/usr --units=GB --warning=10% Monitoring-Plugin-0.40/t/npg03/expected/05_disk10000644000175000017500000000003412267046307017767 0ustar svensvencheck_disk -p /tmp -p /home Monitoring-Plugin-0.40/t/npg03/expected/05_disk40000644000175000017500000000004412267046307017773 0ustar svensvencheck_disk -p /tmp -p /var -p /home Monitoring-Plugin-0.40/t/npg03/expected/02_override20000644000175000017500000000005712267046307020657 0ustar svensvencheck_mysql --password=secret --username=admin Monitoring-Plugin-0.40/t/npg03/expected/09_funnystuff0000644000175000017500000000010212267046307021163 0ustar svensvencheck_disk --expect=" space in front" -p "" --username="Ton Voon" Monitoring-Plugin-0.40/t/npg03/expected/05_disk50000644000175000017500000000004412267046307017774 0ustar svensvencheck_disk -p /var -p /tmp -p /home Monitoring-Plugin-0.40/t/npg03/expected/12_nosection_implicit0000644000175000017500000000003612267046307022647 0ustar svensvencheck_no_section -H localhost Monitoring-Plugin-0.40/t/npg03/expected/00_basic0000644000175000017500000000013512267046307020032 0ustar svensvencheck_mysql -H localhost -S --critical=15 --password=secret --username=altinity --warning=10 Monitoring-Plugin-0.40/t/npg03/plugins.ini0000644000175000017500000000054412267046307017114 0ustar svensven[check_mysql] username=tonvoon password=secret [more_options] username=altinity warning=10 critical=15 [check_disk] p=/tmp [check_2_disks] p=/tmp p=/var [check_2_disks_reprise] p=/var p=/tmp [check_disk2] path=/var path=/home units=GB [funny_stuff] username="Ton Voon" p= expect=" space in front" # Test 3 parameters [check_disk3] p=/ p=/var p=/tmp Monitoring-Plugin-0.40/t/npg03/README0000644000175000017500000000127412267054212015605 0ustar svensvenMonitoring-Plugin-Getopt-03.t automatically tests all cases defined in the 'input' directory and expects the output to match the corresponding file in the 'expected' directory. To define a new test case, just create a new file in the 'input' directory containing the input command line, and a corresponding file in the 'expected' directory containing what you think the expanded command line should be. Note that this expansion is normalised as follows: - command line arguments are reported in alphabetical order - extraneous white space is removed Also, if you use a completely new argument than those currently defined in Monitoring-Plugin-Getopt-03.t you will need to define it there as well. Monitoring-Plugin-0.40/t/Monitoring-Plugin-Getopt-04.t0000644000175000017500000000646112450000372021220 0ustar svensven# Monitoring::Plugin::Getopt spec-to-help generation tests use strict; use Test::More tests => 15; BEGIN { use_ok('Monitoring::Plugin::Getopt') }; # Needed to get evals to work in testing Monitoring::Plugin::Functions::_use_die(1); my %PARAM = ( version => '0.01', usage => "Don't use this plugin!", ); sub setup { # Instantiate object my $ng = Monitoring::Plugin::Getopt->new(%PARAM); ok($ng, 'constructor ok'); # Positional args, no short arguments, INTEGER $ng->arg('warning=i' => qq(Exit with WARNING status if less than INTEGER foobars are free), 5); # Named args, long + short arguments, INTEGER $ng->arg( spec => 'critical|c=i', help => qq(Exit with CRITICAL status if less than INTEGER foobars are free), required => 1, ); # Named args, multiple short arguments, STRING, default expansion $ng->arg( spec => 'x|y|z=s', help => qq(Foobar. Default: %s), default => "XYZ", ); # Named args, multiple mixed, no label $ng->arg( spec => 'long|longer|longest|l', help => qq(Long format), ); # Named args, long + short, explicit label $ng->arg( spec => 'hostname|H=s', label => 'ADDRESS', help => qq(Hostname), ); # Positional args, long only, explicit label $ng->arg('avatar=s', 'Avatar', undef, undef, 'AVATAR'); # Multiline help test, named args $ng->arg( spec => 'disk=s', label => [ qw(BYTES PERCENT%), undef ], help => [ qq(Disk limit in BYTES), qq(Disk limit in PERCENT), qq(Disk limit in FOOBARS (Default: %s)), ], default => 1024, ); # Multiline help test, positional args $ng->arg( 'limit=s', [ qq(Limit in BYTES), qq(Limit in PERCENT), ], undef, undef, [ undef, 'PERCENT%' ], ); # Named args with *optional* but pre-set value $ng->arg( spec => 'dirport|d:9030', help => 'dirport', ); # Named args with *optional* string value $ng->arg( spec => 'enablesomething|s:s', help => 'something', ); # Named args with *optional* integer value (same as ":0") $ng->arg( spec => 'testtimeout|T:i', help => 'testtimeout', ); # Named args with *optional* but increasing integer value $ng->arg( spec => 'verbosity|v:+', help => 'verbosity', ); return $ng; } my $ng; @ARGV = ( '--help' ); $ng = setup; ok(! defined eval { $ng->getopts }, 'getopts died on help'); like($@, qr/\n --warning=INTEGER/, 'warning ok'); like($@, qr/\n -c, --critical=INTEGER/, 'critical ok'); like($@, qr/\n -x, -y, -z=STRING\n Foobar. Default: XYZ\n/, 'x|y|z ok'); like($@, qr/\n -l, --long, --longer, --longest\n Long format\n/, 'long ok'); like($@, qr/\n -H, --hostname=ADDRESS\n Hostname\n/, 'hostname ok'); like($@, qr/\n --avatar=AVATAR\n Avatar\n/, 'avatar ok'); like($@, qr/\n --disk=BYTES\n Disk limit in BYTES\n --disk=PERCENT%\n Disk limit in PERCENT\n --disk=STRING\n Disk limit in FOOBARS \(Default: 1024\)\n/, 'disk multiline ok'); like($@, qr/\n --limit=STRING\n Limit in BYTES\n --limit=PERCENT%\n Limit in PERCENT\n/, 'limit multiline ok'); like($@, qr/\n -d, --dirport\[=INTEGER\]/, 'dirport ok'); like($@, qr/\n -s, --enablesomething\[=STRING\]/, 'enablesomething ok'); like($@, qr/\n -T, --testtimeout\[=INTEGER\]/, 'testtimeout ok'); like($@, qr/\n -v, --verbosity\[=INTEGER\]/, 'verbosity ok'); #print $@; Monitoring-Plugin-0.40/t/Monitoring-Plugin-Functions-01.t0000644000175000017500000001454312677764435021757 0ustar svensven use strict; use Test::More tests => 116; BEGIN { use_ok("Monitoring::Plugin::Functions", ":all"); } Monitoring::Plugin::Functions::_fake_exit(1); my $this_version=$Monitoring::Plugin::Functions::VERSION; foreach my $m ("", qw(::Threshold ::Getopt ::Performance ::Range)) { my $mod = "Monitoring::Plugin$m"; use_ok($mod); # Lots of hackery below. Easier to say $mod->VERSION, but this is probably a recent perl thing my $v = "$mod"."::VERSION"; my $a = eval "\$$v"; is($a, $this_version, "Version number for $mod the same as Functions: $this_version"); } # check get_shortname is(get_shortname, "MONITORING-PLUGIN-FUNCTIONS-01", "get_shortname ok"); # Hardcoded checks of constants ok(%ERRORS, '%ERRORS defined'); is(OK, $ERRORS{OK}, "OK => $ERRORS{OK}"); is(WARNING, $ERRORS{WARNING}, "WARNING => $ERRORS{WARNING}"); is(CRITICAL, $ERRORS{CRITICAL}, "CRITICAL => $ERRORS{CRITICAL}"); is(UNKNOWN, $ERRORS{UNKNOWN}, "UNKNOWN => $ERRORS{UNKNOWN}"); is(DEPENDENT, $ERRORS{DEPENDENT}, "DEPENDENT => $ERRORS{DEPENDENT}"); # Test plugin_exit( CONSTANT, $msg ), plugin_exit( $string, $msg ) my $r; my @ok = ( [ OK, "OK", 'test the first', ], [ WARNING, "WARNING", 'test the second', ], [ CRITICAL, "CRITICAL", 'test the third', ], [ UNKNOWN, "UNKNOWN", 'test the fourth', ], [ DEPENDENT, "DEPENDENT", 'test the fifth', ], ); for (@ok) { # CONSTANT $r = plugin_exit($_->[0], $_->[2]); is($r->return_code, $_->[0], sprintf('plugin_exit(%s, $msg) returned %s', $_->[1], $_->[0])); like($r->message, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_exit(%s, $msg) output matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); # $string $r = plugin_exit($_->[1], $_->[2]); is($r->return_code, $_->[0], sprintf('plugin_exit("%s", $msg) returned %s', $_->[1], $_->[0])); like($r->message, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_exit("%s", $msg) output matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); like($r, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_exit("%s", $msg) stringified matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); } # plugin_exit code corner cases my @ugly1 = ( [ -1, 'testing code -1' ], [ 7, 'testing code 7' ], [ undef, 'testing code undef' ], [ '', qq(testing code '') ], [ 'string', qq(testing code 'string') ], ); for (@ugly1) { $r = plugin_exit($_->[0], $_->[1]); my $display = defined $_->[0] ? "'$_->[0]'" : 'undef'; is($r->return_code, UNKNOWN, "plugin_exit($display, \$msg) returned ". UNKNOWN); like($r->message, qr/UNKNOWN\b.*\b$_->[1]$/, sprintf('plugin_exit(%s, $msg) output matched "%s"', $display, 'UNKNOWN.*' . $_->[1])); } # plugin_exit message corner cases my @ugly2 = ( [ '' ], [ undef ], [ UNKNOWN ], ); for (@ugly2) { $r = plugin_exit(CRITICAL, $_->[0]); my $display1 = defined $_->[0] ? "'$_->[0]'" : "undef"; my $display2 = defined $_->[0] ? $_->[0] : ''; like($r->message, qr/CRITICAL\b.*\b$display2$/, sprintf('plugin_exit(%s, $msg) output matched "%s"', $display1, "CRITICAL.*$display2")); } # plugin_exit message with longoutput my @ugly3 = ( [ "MSG\nLONGOUTPUT", " - MSG\nLONGOUTPUT" ], [ "\nLONGOUTPUT", "\nLONGOUTPUT" ], [ " \nLONGOUTPUT", " \nLONGOUTPUT" ], ); for (@ugly3) { $r = plugin_exit(CRITICAL, $_->[0]); like($r->message, qr/CRITICAL$_->[1]$/, sprintf('plugin_exit(CRITICAL, $msg) output matched "%s"', "CRITICAL$_->[1]")); } # Test plugin_die( $msg ) my @msg = ( [ 'die you dog' ], [ '' ], [ undef ], ); for (@msg) { $r = plugin_die($_->[0]); my $display1 = defined $_->[0] ? "'$_->[0]'" : "undef"; my $display2 = defined $_->[0] ? $_->[0] : ''; is($r->return_code, UNKNOWN, sprintf('plugin_die(%s) returned UNKNOWN', $display1)); like($r->message, qr/UNKNOWN\b.*\b$display2$/, sprintf('plugin_die(%s) output matched "%s"', $display1, "UNKNOWN.*$display2")); } # Test plugin_die( CONSTANT, $msg ), plugin_die( $msg, CONSTANT ), # plugin_die( $string, $msg ), and plugin_die( $msg, $string ) @ok = ( [ OK, "OK", 'test the first', ], [ WARNING, "WARNING", 'test the second', ], [ CRITICAL, "CRITICAL", 'test the third', ], [ UNKNOWN, "UNKNOWN", 'test the fourth', ], [ DEPENDENT, "DEPENDENT", 'test the fifth', ], ); for (@ok) { # CONSTANT, $msg $r = plugin_die($_->[0], $_->[2]); is($r->return_code, $_->[0], sprintf('plugin_die(%s, $msg) returned %s', $_->[1], $_->[0])); like($r->message, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_die(%s, $msg) output matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); # $msg, CONSTANT $r = plugin_die($_->[2], $_->[0]); is($r->return_code, $_->[0], sprintf('plugin_die($msg, %s) returned %s', $_->[1], $_->[0])); like($r->message, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_die($msg, %s) output matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); # $string, $msg $r = plugin_die($_->[1], $_->[2]); is($r->return_code, $_->[0], sprintf('plugin_die("%s", $msg) returned %s', $_->[1], $_->[0])); like($r->message, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_die("%s", $msg) output matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); like($r, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_die("%s", $msg) stringified matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); # $string, $msg $r = plugin_die($_->[2], $_->[1]); is($r->return_code, $_->[0], sprintf('plugin_die($msg, "%s") returned %s', $_->[1], $_->[0])); like($r->message, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_die($msg, "%s") output matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); like($r, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_die($msg, "%s") stringified matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); } # Check that _use_die set to 1 will catch exceptions correctly Monitoring::Plugin::Functions::_fake_exit(0); Monitoring::Plugin::Functions::_use_die(1); eval { plugin_die("Using die") }; is( $@, "MONITORING-PLUGIN-FUNCTIONS-01 UNKNOWN - Using die\n", "Caught exception"); Monitoring-Plugin-0.40/t/Monitoring-Plugin-Getopt-01.t0000644000175000017500000001305113030447123021212 0ustar svensven# Monitoring::Plugin::Getopt basic tests use strict; use Test::More tests => 81; BEGIN { use_ok('Monitoring::Plugin::Getopt') }; # Needed to get evals to work in testing Monitoring::Plugin::Functions::_use_die(1); my %PARAM = ( version => '0.01', url => 'http://www.openfusion.com.au/labs/nagios/', blurb => 'This plugin tests various stuff.', usage => "Usage: %s -H -w -c ", plugin => 'test_plugin', ); sub setup { # Instantiate object my $ng = Monitoring::Plugin::Getopt->new(%PARAM); ok($ng, 'constructor ok'); # Add argument - short form - arg spec, help text, default, required? $ng->arg('warning|w=s' => qq(-w, --warning=INTEGER\n Exit with WARNING status if less than INTEGER foobars are free), 5); # Add argument - named version $ng->arg( spec => 'critical|c=i', help => qq(Exit with CRITICAL status if less than INTEGER foobars are free), required => 1, ); # Add argument - boolean, supporting --no-prefix $ng->arg( spec => 'perfdata!', help => qq(Provide performance data), default => 1, ); return $ng; } my $ng; # Simple usage (short and long args) @ARGV = qw(-w 3 --critical 10 --timeout=12 --verbose); $ng = setup; $ng->getopts; is($ng->warning, 3, 'warning set to 3'); is($ng->critical, 10, 'critical set to 10'); is($ng->timeout, 12, 'timeout set to 12'); is($ng->perfdata, 1, 'perfdata set to default of 1'); # Disable perfdata @ARGV = qw(--critical 10 --no-perfdata); $ng = setup; $ng->getopts; is($ng->perfdata, 0, 'perfdata set to 0'); # Check multiple verbose flags @ARGV = qw(-w 3 --critical 10 -v -v -v); $ng = setup; $ng->getopts; is ($ng->verbose, 3, "Verbose set to level 3"); @ARGV = qw(-w 3 --critical 10 --verbose --verbose --verbose); $ng = setup; $ng->getopts; is ($ng->verbose, 3, "Verbose set to level 3 (longhand)"); # Missing args @ARGV = qw(); $ng = setup; ok(! defined eval { $ng->getopts }, 'getopts died on missing args'); like($@, qr/Usage:/, 'usage message'); like($@, qr/Missing arg/, 'missing arguments'); is($ng->verbose, 0, 'verbose set to 0'); # Missing critical @ARGV = qw(-w0 -v); $ng = setup; ok(! defined eval { $ng->getopts }, 'getopts died on missing args'); like($@, qr/Usage:/, 'usage message'); like($@, qr/Missing argument: critical/, 'missing argument: critical'); unlike($@, qr/Missing argument: warning/, 'no missing argument: warning'); is($ng->warning, 0, 'warning set to 0'); is($ng->critical, undef, 'critical undef'); is($ng->timeout, 15, 'timeout set to default'); is($ng->verbose, 1, 'verbose set to true'); # Missing warning @ARGV = qw(--critical=27 --timeout 17 --verbose); $ng = setup; $ng->getopts; is($ng->warning, 5, 'warning 5 (default)'); is($ng->critical, 27, 'critical set to 27'); is($ng->timeout, 17, 'timeout set to 17'); is($ng->verbose, 1, 'verbose set to true'); # -? --usage @ARGV = ( '-?' ); $ng = setup; ok(! defined eval { $ng->getopts }, 'getopts died on usage'); like($@, qr/Usage:/, 'usage message'); unlike($@, qr/Missing arg/, 'no missing arguments'); @ARGV = ( '--usage' ); $ng = setup; ok(! defined eval { $ng->getopts }, 'getopts died on usage'); like($@, qr/Usage:/, 'usage message'); unlike($@, qr/Missing arg/, 'no missing arguments'); # -V --version @ARGV = ( '-V' ); $ng = setup; ok(! defined eval { $ng->getopts }, 'getopts died on version'); like($@, qr/^$PARAM{plugin}/, 'version info includes plugin name'); like($@, qr/$PARAM{version}/, 'version info includes version'); like($@, qr/$PARAM{url}/, 'version info includes url'); unlike($@, qr/Usage:/, 'no usage message'); unlike($@, qr/Missing arg/, 'no missing arguments'); @ARGV = ( '--version' ); $ng = setup; ok(! defined eval { $ng->getopts }, 'getopts died on version'); like($@, qr/^$PARAM{plugin}/, 'version info includes plugin name'); like($@, qr/$PARAM{version}/, 'version info includes version'); like($@, qr/$PARAM{url}/, 'version info includes url'); unlike($@, qr/Usage:/, 'no usage message'); unlike($@, qr/Missing arg/, 'no missing arguments'); # -h --help @ARGV = ( '-h' ); $ng = setup; ok(! defined eval { $ng->getopts }, 'getopts died on help'); like($@, qr/^$PARAM{plugin}/, 'help includes plugin name'); like($@, qr/$PARAM{version}/, 'help includes version'); like($@, qr/$PARAM{url}/, 'help includes url'); like($@, qr/General Public Licence/, 'help includes licence'); like($@, qr/$PARAM{blurb}/, 'help includes blurb'); like($@, qr/Usage:/, 'help includes usage message'); like($@, qr/--version/, 'help includes default options 1'); like($@, qr/--verbose/, 'help includes default options 2'); like($@, qr/--warning/, 'help includes custom option 1'); like($@, qr/--critical/, 'help includes custom option 2'); like($@, qr/--\[no-\]perfdata\n/, 'help includes custom option 3'); unlike($@, qr/Missing arg/, 'no missing arguments'); @ARGV = ( '--help' ); $ng = setup; ok(! defined eval { $ng->getopts }, 'getopts died on help'); like($@, qr/^$PARAM{plugin}/, 'help includes plugin name'); like($@, qr/$PARAM{version}/, 'help includes version'); like($@, qr/$PARAM{url}/, 'help includes url'); like($@, qr/General Public Licence/, 'help includes licence'); like($@, qr/$PARAM{blurb}/, 'help includes blurb'); like($@, qr/Usage:/, 'help includes usage message'); like($@, qr/--version/, 'help includes default options 1'); like($@, qr/--verbose/, 'help includes default options 2'); like($@, qr/--warning/, 'help includes custom option 1'); like($@, qr/-c, --critical=INTEGER/, 'help includes custom option 2, with expanded args'); like($@, qr/--\[no-\]perfdata\n/, 'help includes custom option 3'); unlike($@, qr/Missing arg/, 'no missing arguments'); Monitoring-Plugin-0.40/t/Monitoring-Plugin-05.t0000644000175000017500000000061012267053561017765 0ustar svensven# Check for exported vars # Can't include Monitoring::Plugin::Functions because it also exports %STATUS_TEXT use strict; use Test::More tests=>4; BEGIN { use_ok('Monitoring::Plugin') }; eval ' $_ = $STATUS_TEXT{0} '; like( $@, '/Global symbol "%STATUS_TEXT" requires explicit package name/' ); use_ok("Monitoring::Plugin", qw(%STATUS_TEXT)); eval ' $_ = $STATUS_TEXT{0} '; is( $@, '' ); Monitoring-Plugin-0.40/t/check_stuff.t0000755000175000017500000000303113076140206016441 0ustar svensven#!/usr/local/bin/perl # use strict; use warnings; #use Test::More qw(no_plan); use Test::More tests => 14; my ($r,$args); my $s = 't/check_stuff.pl'; $s = "$^X -Ilib $s"; my $n = 'STUFF'; # Monitoring status strings and exit codes my %e = qw( OK 0 WARNING 1 CRITICAL 2 UNKNOWN 3 ); $r = `$s`; is $?>>8 , $e{UNKNOWN}, "exits($e{UNKNOWN}) with no args"; like $r, qr/^$n UNKNOWN/, "UNKNOWN with no args"; $r = `$s -V`; is $?>>8 , $e{UNKNOWN}, "exits($e{UNKNOWN}) with -V arg"; like $r, qr/^[\w\.]+ \d+/i, "looks like there's a version"; $r = `$s -h`; is $?>>8 , $e{UNKNOWN}, "exits($e{UNKNOWN}) with -h arg"; like $r, qr/usage/i, "looks like there's something helpful"; # broken $args = " -r 99 "; diag "running `$s $args`" if $ENV{TEST_VERBOSE}; $r = `$s $args`; diag "output: '$r'" if $ENV{TEST_VERBOSE}; is $?>>8 , $e{UNKNOWN}, "exits($e{UNKNOWN}) with $args"; like $r, qr/UNKNOWN.+invalid/i, "UNKNOWN (warning: invalid -r) with $args"; my $expected = { " -w 10:15 -c~:15 -r 0" => 'WARNING', " -w 10:15 -c~:15 -r 11" => 'OK', " -w 10:15 -c~:15 -r 15.8" => 'CRITICAL', }; test_expected( $s, $expected ); sub test_expected { my $s = shift; my $expected = shift; foreach ( keys %$expected ) { diag "running `$s $_`" if $ENV{TEST_VERBOSE}; $r = `$s $_`; diag "output: '$r'" if $ENV{TEST_VERBOSE}; is $?>>8 , $e{$expected->{$_}}, "exits($e{$expected->{$_}}) with $_"; like $r, qr/^$n $expected->{$_}/i, "looks $expected->{$_} with $_"; } } Monitoring-Plugin-0.40/t/Monitoring-Plugin-Getopt-02.t0000644000175000017500000000271212267053357021232 0ustar svensven# Monitoring::Plugin::Getopt timeout tests use strict; use Test::More tests => 14; BEGIN { use_ok('Monitoring::Plugin::Getopt') }; # Needed to get evals to work in testing Monitoring::Plugin::Functions::_use_die(1); my %PARAM = ( version => '0.01', url => 'http://www.openfusion.com.au/labs/nagios/', blurb => 'This plugin tests various stuff.', usage => "Usage: %s -H -w -c ", plugin => 'test_plugin', timeout => 18, ); sub setup { # Instantiate object my $ng = Monitoring::Plugin::Getopt->new(%PARAM); ok($ng, 'constructor ok'); return $ng; } my $ng; # No args @ARGV = qw(); $ng = setup(); $ng->getopts; is($ng->timeout, 18, 'default timeout set to 18'); # Check help message @ARGV = ( '-h' ); $ng = setup; ok(! defined eval { $ng->getopts }, 'getopts died on help'); like($@, qr/times out.*default: 18\b/i, 'help timeout changed to 18'); # Explicit timeout @ARGV = qw(--timeout=25 --verbose); $ng = setup(); $ng->getopts; is($ng->timeout, 25, 'timeout changed to 25'); # Explicit timeout @ARGV = qw(-t10 --verbose); $ng = setup(); $ng->getopts; is($ng->timeout, 10, 'timeout changed to 10'); # Short timeout, test default timeout handler @ARGV = qw(-t2 --verbose); $ng = setup(); $ng->getopts; is($ng->timeout, 2, 'timeout changed to 2'); alarm($ng->timeout); # Loop ok(! defined eval { 1 while 1 }, 'loop timed out'); like($@, qr/UNKNOWN\b.*\btimed out/, 'default timeout handler ok'); Monitoring-Plugin-0.40/t/Monitoring-Plugin-Functions-04.t0000644000175000017500000000123012267053410021722 0ustar svensven# max_state_alt tests use strict; use Test::More tests => 8; BEGIN { use_ok("Monitoring::Plugin::Functions", ":all") } my $new_state = max_state_alt( OK, WARNING ); is( $new_state, WARNING, "Moved up to WARNING" ); is( max_state_alt( $new_state, UNKNOWN ), WARNING, "Still at WARNING" ); $new_state = max_state_alt( $new_state, CRITICAL ); is( $new_state, CRITICAL, "Now at CRITICAL" ); is( max_state_alt( OK, OK ), OK, "This is OK" ); is( max_state_alt( OK, UNKNOWN ), UNKNOWN, "This is UNKNOWN" ); is( max_state_alt( OK, OK, OK, OK, OK, WARNING ), WARNING, "Use WARNING in this list" ); is( max_state_alt(), UNKNOWN, "Return UNKNOWN if no parameters" ); Monitoring-Plugin-0.40/t/Monitoring-Plugin-Performance-02.t0000644000175000017500000000073312267053271022225 0ustar svensven use strict; use Test::More tests => 3; use_ok("Monitoring::Plugin::Performance", use_die => 1); eval { Monitoring::Plugin::Functions::plugin_die("Testing") }; is( $@, "MONITORING-PLUGIN-PERFORMANCE-02 UNKNOWN - Testing\n", "use_die correctly set on import"); use_ok("Monitoring::Plugin::Performance"); eval { Monitoring::Plugin::Functions::plugin_die("Test OK exit", 0) }; fail("Should not get here if code works correctly because prior plugin_die should have exited"); Monitoring-Plugin-0.40/t/Monitoring-Plugin-Functions-02.t0000644000175000017500000001456412267053417021745 0ustar svensven# check_messages tests use strict; use Test::More tests => 37; BEGIN { use_ok("Monitoring::Plugin::Functions", ":all") } my ($code, $message); # ------------------------------------------------------------------------- # Check codes my @codes = ( [ [ qw(Critical) ], [ qw(Warning) ], CRITICAL ], [ [], [ qw(Warning) ], WARNING ], [ [], [], OK ], ); my $i = 0; for (@codes) { $i++; $code = check_messages( critical => $_->[0], warning => $_->[1] ); is($code, $_->[2], "Code test $i returned $STATUS_TEXT{$_->[2]}"); } # ------------------------------------------------------------------------- # Check messages my %arrays = ( critical => [ qw(A B C) ], warning => [ qw(D E F) ], ok => [ qw(G H I) ], ); my %messages = map { $_ => join(' ', @{$arrays{$_}}) } keys %arrays; # critical, warning ($code, $message) = check_messages( critical => $arrays{critical}, warning => $arrays{warning}, ); is($code, CRITICAL, "(critical, warning) code is $STATUS_TEXT{$code}"); is($message, $messages{critical}, "(critical, warning) message is $message"); # critical, warning, ok ($code, $message) = check_messages( critical => $arrays{critical}, warning => $arrays{warning}, ok => $arrays{ok}, ); is($code, CRITICAL, "(critical, warning, ok) code is $STATUS_TEXT{$code}"); is($message, $messages{critical}, "(critical, warning, ok) message is $message"); # critical, warning, $ok ($code, $message) = check_messages( critical => $arrays{critical}, warning => $arrays{warning}, ok => 'G H I', ); is($code, CRITICAL, "(critical, warning, \$ok) code is $STATUS_TEXT{$code}"); is($message, $messages{critical}, "(critical, warning, \$ok) message is $message"); # warning ($code, $message) = check_messages( critical => [], warning => $arrays{warning}, ); is($code, WARNING, "(warning) code is $STATUS_TEXT{$code}"); is($message, $messages{warning}, "(warning) message is $message"); # warning, ok ($code, $message) = check_messages( critical => [], warning => $arrays{warning}, ok => $arrays{ok}, ); is($code, WARNING, "(warning, ok) code is $STATUS_TEXT{$code}"); is($message, $messages{warning}, "(warning, ok) message is $message"); # ok ($code, $message) = check_messages( critical => [], warning => [], ok => $arrays{ok}, ); is($code, OK, "(ok) code is $STATUS_TEXT{$code}"); is($message, $messages{ok}, "(ok) message is $message"); # $ok ($code, $message) = check_messages( critical => [], warning => [], ok => 'G H I', ); is($code, OK, "(\$ok) code is $STATUS_TEXT{$code}"); is($message, $messages{ok}, "(\$ok) message is $message"); # ------------------------------------------------------------------------- # explicit join my $join = '+'; ($code, $message) = check_messages( critical => $arrays{critical}, warning => $arrays{warning}, join => $join, ); is($message, join($join, @{$arrays{critical}}), "joined '$join' (critical, warning) message is $message"); $join = ''; ($code, $message) = check_messages( critical => [], warning => $arrays{warning}, join => $join, ); is($message, join($join, @{$arrays{warning}}), "joined '$join' (warning) message is $message"); $join = undef; ($code, $message) = check_messages( critical => [], warning => [], ok => $arrays{ok}, join => $join, ); is($message, join(' ', @{$arrays{ok}}), "joined undef (ok) message is $message"); # ------------------------------------------------------------------------- # join_all messages my $join_all = ' :: '; my $msg_all_cwo = join($join_all, map { join(' ', @{$arrays{$_}}) } qw(critical warning ok)); my $msg_all_cw = join($join_all, map { join(' ', @{$arrays{$_}}) } qw(critical warning)); my $msg_all_wo = join($join_all, map { join(' ', @{$arrays{$_}}) } qw(warning ok)); # critical, warning, ok ($code, $message) = check_messages( critical => $arrays{critical}, warning => $arrays{warning}, ok => $arrays{ok}, join_all => $join_all, ); is($code, CRITICAL, "(critical, warning, ok) code is $STATUS_TEXT{$code}"); is($message, $msg_all_cwo, "join_all '$join_all' (critical, warning, ok) message is $message"); # critical, warning, $ok ($code, $message) = check_messages( critical => $arrays{critical}, warning => $arrays{warning}, ok => 'G H I', join_all => $join_all, ); is($code, CRITICAL, "(critical, warning, \$ok) code is $STATUS_TEXT{$code}"); is($message, $msg_all_cwo, "join_all '$join_all' (critical, warning, \$ok) message is $message"); # critical, warning ($code, $message) = check_messages( critical => $arrays{critical}, warning => $arrays{warning}, join_all => $join_all, ); is($code, CRITICAL, "(critical, warning) code is $STATUS_TEXT{$code}"); is($message, $msg_all_cw, "join_all '$join_all' (critical, warning) message is $message"); # warning, ok ($code, $message) = check_messages( critical => [], warning => $arrays{warning}, ok => $arrays{ok}, join_all => $join_all, ); is($code, WARNING, "(warning, ok) code is $STATUS_TEXT{$code}"); is($message, $msg_all_wo, "join_all '$join_all' (critical, warning, ok) message is $message"); # warning, $ok ($code, $message) = check_messages( critical => [], warning => $arrays{warning}, ok => 'G H I', join_all => $join_all, ); is($code, WARNING, "(warning, \$ok) code is $STATUS_TEXT{$code}"); is($message, $msg_all_wo, "join_all '$join_all' (critical, warning, \$ok) message is $message"); # warning ($code, $message) = check_messages( critical => [], warning => $arrays{warning}, join_all => $join_all, ); is($code, WARNING, "(warning) code is $STATUS_TEXT{$code}"); is($message, 'D E F', "join_all '$join_all' (critical, warning) message is $message"); # ------------------------------------------------------------------------- # Error cases # Test failures without required fields ok(! defined eval { ($code, $message) = check_messages() }, "check_messages dies without message args"); ok(! defined eval { ($code, $message) = check_messages(warning => $arrays{warning}) }, "check_messages dies without 'critical' message"); ok(! defined eval { ($code, $message) = check_messages(critical => $arrays{critical}) }, "check_messages dies without 'warning' message"); ok(defined eval { ($code, $message) = check_messages(critical => $arrays{critical}, warning => $arrays{warning}) }, "check_messages ok with 'critical' and 'warning' messages"); Monitoring-Plugin-0.40/t/Monitoring-Plugin-Range.t0000644000175000017500000001740513076140206020577 0ustar svensven use strict; #use Test::More qw(no_plan); use Test::More tests => 151; BEGIN { use_ok('Monitoring::Plugin::Range'); # Silence warnings unless TEST_VERBOSE is set $SIG{__WARN__} = sub { warn $_[0] if $ENV{TEST_VERBOSE} }; }; diag "\nusing Monitoring::Plugin::Range revision ". $Monitoring::Plugin::Range::VERSION . "\n" if $ENV{TEST_VERBOSE}; my $r; diag "'garbage in' checks -- you should see 7 invalid range definition warnings here:" if $ENV{TEST_VERBOSE}; foreach (qw( : 1:~ foo 1-10 10:~ 1-10:2.4 ), '1,10' # avoid warning about using , inside qw() ) { $r =Monitoring::Plugin::Range->parse_range_string($_); is $r, undef, "'$_' should not be a valid range" ; } diag "range: 0..6 inclusive" if $ENV{TEST_VERBOSE}; $r = Monitoring::Plugin::Range->parse_range_string("6"); isa_ok( $r, "Monitoring::Plugin::Range"); ok( defined $r, "'6' is valid range"); cmp_ok( $r->start, '==', 0, "Start correct"); cmp_ok( $r->start_infinity, '==', 0, "Not using negative infinity"); cmp_ok( $r->end, '==', 6, "End correct"); cmp_ok( $r->end_infinity, '==', 0, "Not using positive infinity"); cmp_ok( $r, 'eq', "6", "Stringification back to original"); my $expected = { -1 => 1, # 1 means it raises an alert because it's OUTSIDE the range 0 => 0, # 0 means it's inside the range (no alert) 4 => 0, 6 => 0, 6.1 => 1, 79.999999 => 1, }; sub test_expected { my $r = shift; my $expected = shift; foreach (sort {$a<=>$b} keys %$expected) { is $r->check_range($_), $expected->{$_}, " $_ should " . ($expected->{$_} ? 'not ' : '') . "be in the range (line ".(caller)[2].")"; } } test_expected( $r, $expected ); diag "range : -7..23, inclusive" if $ENV{TEST_VERBOSE}; $r = Monitoring::Plugin::Range->parse_range_string("-7:23"); ok( defined $r, "'-7:23' is valid range"); cmp_ok( $r->start, '==', -7, "Start correct"); cmp_ok( $r->start_infinity, '==', 0, "Not using negative infinity"); cmp_ok( $r->end, '==', 23, "End correct"); cmp_ok( $r->end_infinity, '==', 0, "Not using positive infinity"); cmp_ok( $r, 'eq', "-7:23", "Stringification back to original"); $expected = { -23 => 1, -7 => 0, -1 => 0, 0 => 0, 4 => 0, 23 => 0, 23.1 => 1, 79.999999 => 1, }; test_expected( $r, $expected ); diag "range : 0..5.75, inclusive" if $ENV{TEST_VERBOSE}; $r = Monitoring::Plugin::Range->parse_range_string(":5.75"); ok( defined $r, "':5.75' is valid range"); cmp_ok( $r->start, '==', 0, "Start correct"); cmp_ok( $r->start_infinity, '==', 0, "Not using negative infinity"); cmp_ok( $r->end, '==', 5.75, "End correct"); cmp_ok( $r->end_infinity, '==', 0, "Not using positive infinity"); cmp_ok( $r, 'eq', "5.75", "Stringification to simplification"); $expected = { -1 => 1, 0 => 0, 4 => 0, 5.75 => 0, 5.7501 => 1, 6 => 1, 6.1 => 1, 79.999999 => 1, }; test_expected( $r, $expected ); diag "range : negative infinity .. -95.99, inclusive" if $ENV{TEST_VERBOSE}; $r = Monitoring::Plugin::Range->parse_range_string("~:-95.99"); ok( defined $r, "'~:-95.99' is valid range"); cmp_ok( $r->start_infinity, '==', 1, "Using negative infinity"); cmp_ok( $r->end, '==', -95.99, "End correct"); cmp_ok( $r->end_infinity, '==', 0, "Not using positive infinity"); cmp_ok( $r, 'eq', "~:-95.99", "Stringification back to original"); $expected = { -1001341 => 0, -96 => 0, -95.999 => 0, -95.99 => 0, -95.989 => 1, -95 => 1, 0 => 1, 5.7501 => 1, 79.999999 => 1, }; test_expected( $r, $expected ); diag "range 10..infinity , inclusive" if $ENV{TEST_VERBOSE}; test_expected( $r, $expected ); $r = Monitoring::Plugin::Range->parse_range_string("10:"); ok( defined $r, "'10:' is valid range"); cmp_ok( $r->start, '==', 10, "Start correct"); cmp_ok( $r->start_infinity, '==', 0, "Not using negative infinity"); cmp_ok( $r->end_infinity, '==', 1, "Using positive infinity"); cmp_ok( $r, 'eq', "10:", "Stringification back to original"); $expected = { -95.999 => 1, -1 => 1, 0 => 1, 9.91 => 1, 10 => 0, 11.1 => 0, 123456789012346 => 0, }; test_expected( $r, $expected ); diag "range 123456789012345..infinity , inclusive" if $ENV{TEST_VERBOSE}; test_expected( $r, $expected ); $r = Monitoring::Plugin::Range->parse_range_string("123456789012345:"); ok( defined $r, "'123456789012345:' is valid range"); cmp_ok( $r->start, '==', 123456789012345, "Start correct"); cmp_ok( $r->start_infinity, '==', 0, "Not using negative infinity"); cmp_ok( $r->end_infinity, '==', 1, "Using positive infinity"); cmp_ok( $r, 'eq', "123456789012345:", "Stringification back to original"); $expected = { -95.999 => 1, -1 => 1, 0 => 1, # The fractional values needs to be quoted, otherwise the hash rounds it up to ..345 # and there is one less test run. # I think some newer versions of perl use a higher precision value for the hash key. # This doesn't appear to affect the actual plugin though "123456789012344.91" => 1, 123456789012345 => 0, "123456789012345.61" => 0, 123456789012346 => 0, }; test_expected( $r, $expected ); diag "range: <= zero " if $ENV{TEST_VERBOSE}; $r = Monitoring::Plugin::Range->parse_range_string("~:0"); ok( defined $r, "'~:0' is valid range"); cmp_ok( $r->start_infinity, '==', 1, "Using negative infinity"); cmp_ok( $r->end, '==', 0, "End correct"); cmp_ok( $r->end_infinity, '==', 0, "Not using positive infinity"); cmp_ok( $r->alert_on, '==', 0, "Will alert on outside of range"); cmp_ok( $r, 'eq', "~:0", "Stringification back to original"); ok( $r->check_range(0.5) == 1, "0.5 - alert"); ok( $r->check_range(-10) == 0, "-10 - no alert"); ok( $r->check_range(0) == 0, "0 - no alert"); $expected = { -123456789012344.91 => 0, -1 => 0, 0 => 0, .001 => 1, 123456789012345 => 1, }; test_expected( $r, $expected ); diag "range: OUTSIDE 0..657.8210567" if $ENV{TEST_VERBOSE}; $r = Monitoring::Plugin::Range->parse_range_string('@0:657.8210567'); ok( defined $r, '"@0:657.8210567" is a valid range'); cmp_ok( $r->start, '==', 0, "Start correct"); cmp_ok( $r->start_infinity, '==', 0, "Not using negative infinity"); cmp_ok( $r->end, '==', 657.8210567, "End correct"); cmp_ok( $r->end_infinity, '==', 0, "Not using positive infinity"); cmp_ok( $r->alert_on, '==', 1, "Will alert on inside of range"); cmp_ok( $r, 'eq', '@657.8210567', "Stringification to simplified version"); ok( $r->check_range(32.88) == 1, "32.88 - alert"); ok( $r->check_range(-2) == 0, "-2 - no alert"); ok( $r->check_range(657.8210567) == 1, "657.8210567 - alert"); ok( $r->check_range(0) == 1, "0 - alert"); $expected = { -134151 => 0, -1 => 0, 0 => 1, .001 => 1, 657.8210567 => 1, 657.9 => 0, 123456789012345 => 0, }; test_expected( $r, $expected ); diag "range: 1..1 inclusive (equals one)" if $ENV{TEST_VERBOSE}; $r = Monitoring::Plugin::Range->parse_range_string('1:1'); ok( defined $r, '"1:1" is a valid range'); cmp_ok( $r->start, '==', 1, "Start correct"); cmp_ok( $r->start_infinity, '==', 0, "Not using negative infinity"); cmp_ok( $r->end, '==', 1, "End correct"); cmp_ok( $r->end_infinity, '==', 0, "Not using positive infinity"); cmp_ok( $r, 'eq', "1:1", "Stringification to simplified version"); ok( $r->check_range(0.5) == 1, "0.5 - alert"); ok( $r->check_range(1) == 0, "1 - no alert"); ok( $r->check_range(5.2) == 1, "5.2 - alert"); $expected = { -1 => 1, 0 => 1, .5 => 1, 1 => 0, 1.001 => 1, 5.2 => 1, }; test_expected( $r, $expected ); $r = Monitoring::Plugin::Range->parse_range_string('2:1'); ok( ! defined $r, '"2:1" is rejected'); # TODO: Need more tests for invalid data Monitoring-Plugin-0.40/t/Monitoring-Plugin-Threshold.t0000644000175000017500000001763412267053142021506 0ustar svensven use strict; use Test::More tests => 93; BEGIN { use_ok('Monitoring::Plugin::Threshold'); use_ok('Monitoring::Plugin::Functions', ':all' ); # Silence warnings unless TEST_VERBOSE is set $SIG{__WARN__} = sub { warn $_[0] if $ENV{TEST_VERBOSE} }; } diag "\nusing Monitoring::Plugin::Threshold revision ". $Monitoring::Plugin::Threshold::VERSION . "\n" if $ENV{TEST_VERBOSE}; Monitoring::Plugin::Functions::_fake_exit(1); my $t; $t = Monitoring::Plugin::Threshold->set_thresholds(warning => undef, critical => undef); ok( defined $t, "two undefs" ); ok( ! $t->warning->is_set, "warning not set" ); ok( ! $t->critical->is_set, "critical not set" ); $t = Monitoring::Plugin::Threshold->set_thresholds(warning => "", critical => ""); ok( defined $t, "two empty strings" ); ok( ! $t->warning->is_set, "warning not set" ); ok( ! $t->critical->is_set, "critical not set" ); diag "threshold: critical if > 80" if $ENV{TEST_VERBOSE}; my $t = Monitoring::Plugin::Threshold->set_thresholds(critical => "80"); ok( defined $t, "Threshold ('', '80') set"); ok( ! $t->warning->is_set, "Warning not set"); cmp_ok( $t->critical->start, '==', 0, "Critical strat set correctly"); cmp_ok( $t->critical->end, '==', 80, "Critical end set correctly"); ok ! $t->critical->end_infinity, "not forever"; my $expected = { qw( -1 CRITICAL 4 OK 79.999999 OK 80 OK 80.1 CRITICAL 102321 CRITICAL ) }; sub test_expected_statuses { my $t = shift; my $expected = shift; my $debug = shift; foreach (sort {$a<=>$b} keys %$expected) { is $STATUS_TEXT{$t->get_status($_)}, $expected->{$_}, " $_ - $expected->{$_}"; if ($debug) { diag "val = $_; critical check = ".$t->critical->check_range($_). "; warning check = ".$t->warning->check_range($_); } } use Data::Dumper; diag "thresh dump: ". Dumper $t if $debug; } test_expected_statuses( $t, $expected ); # GMC: this test seems bogus to me - either we've died, in which case internal # state is undefined (and untestable!), or we should be returning a non-fatal error if (0) { diag "threshold: warn if less than 5 or more than 33." if $ENV{TEST_VERBOSE}; eval { $t = Monitoring::Plugin::Threshold->set_thresholds(warning => "5:33", critical => "") }; ok( defined $t, "Threshold ('5:33', '') set"); cmp_ok( $t->warning->start, '==', 5, "Warning start set"); cmp_ok( $t->warning->end, '==', 33, "Warning end set"); ok( ! $t->critical->is_set, "Critical not set"); } # GC: same as previous test, except critical is undef instead of '' diag "threshold: warn if less than 5 or more than 33." if $ENV{TEST_VERBOSE}; $t = Monitoring::Plugin::Threshold->set_thresholds(warning => "5:33", critical => undef); ok( defined $t, "Threshold ('5:33', '') set"); cmp_ok( $t->warning->start, '==', 5, "Warning start set"); cmp_ok( $t->warning->end, '==', 33, "Warning end set"); ok( ! $t->critical->is_set, "Critical not set"); $expected = { qw( -1 WARNING 4 WARNING 4.999999 WARNING 5 OK 14.21 OK 33 OK 33.01 WARNING 10231 WARNING ) }; test_expected_statuses( $t, $expected ); diag "threshold: warn if more than 30; critical if > 60" if $ENV{TEST_VERBOSE}; $t = Monitoring::Plugin::Threshold->set_thresholds(warning => "~:30", critical => "~:60"); ok( defined $t, "Threshold ('~:30', '~:60') set"); cmp_ok( $t->warning->end, '==', 30, "Warning end set"); cmp_ok( $t->critical->end, '==',60, "Critical end set"); ok $t->critical->start_infinity, "Critical starts at negative infinity"; $expected = { qw( -1 OK 4 OK 29.999999 OK 30 OK 30.1 WARNING 50.90 WARNING 59.9 WARNING 60 WARNING 60.00001 CRITICAL 10231 CRITICAL ) }; test_expected_statuses( $t, $expected ); # "I'm going to die homeless, penniless, and 30 pounds overweight." # "...and that's...okay." # TODO: figure out why this doesn't work and fix the test. goto SKIP_DEATH; diag "threshold: test pure crap for arguments - default to OK." if $ENV{TEST_VERBOSE}; diag "you should see one invalid range definition warning and an UNKNOWN line here:\n"; Monitoring::Plugin::Functions->print_on_die(1); Monitoring::Plugin::Functions->exit_on_die(1); dies_ok( sub { $t = Monitoring::Plugin::Threshold->set_thresholds( warning => "total", critical => "rubbish" ) }, "bad thresholds cause death" ); Monitoring::Plugin::Functions->print_on_die(0); Monitoring::Plugin::Functions->exit_on_die(0); SKIP_DEATH: diag "threshold: critical if > 25 " if $ENV{TEST_VERBOSE}; $t = Monitoring::Plugin::Threshold->set_thresholds( critical => "~:25" ); ok( defined $t, "Threshold ('', '~:25') set (".$t->critical.")" ); ok( ! $t->warning->is_set, "Warning not set"); cmp_ok( $t->critical->end, '==',25, "Critical end set"); ok $t->critical->start_infinity, "Critical starts at negative infinity"; $expected = { qw( -1 OK 4 OK 10 OK 14.21 OK 25 OK 25.01 CRITICAL 31001 CRITICAL ) }; test_expected_statuses( $t, $expected); diag "threshold: warn if OUTSIDE {10..25} , critical if > 25 " if $ENV{TEST_VERBOSE}; $t = Monitoring::Plugin::Threshold->set_thresholds(warning => "10:25", critical => "~:25"); ok( defined $t, "Threshold ('10:25', '~:25') set"); cmp_ok( $t->warning->start, '==', 10, "Warning start set"); cmp_ok( $t->warning->end, '==', 25, "Warning end set"); cmp_ok( $t->critical->end, '==', 25, "Critical end set"); $expected = { qw( -1 WARNING 4 WARNING 9.999999 WARNING 10 OK 14.21 OK 25 OK 25.01 CRITICAL 31001 CRITICAL ) }; test_expected_statuses( $t, $expected ); diag "warn if INSIDE {10..25} , critical if < 10 " if $ENV{TEST_VERBOSE}; $t = Monitoring::Plugin::Threshold->set_thresholds(warning => "\@10:25", critical => "10:"); $expected = { qw( -1 CRITICAL 4 CRITICAL 9.999999 CRITICAL 10 WARNING 14.21 WARNING 25 WARNING 25.01 OK 31001 OK ) }; test_expected_statuses( $t, $expected ); # GMC: as of 0.16, set_thresholds can also be called as a mutator diag "threshold mutator: warn if more than 30; critical if > 60" if $ENV{TEST_VERBOSE}; my $t1 = $t; $t->set_thresholds(warning => "0:45", critical => "0:90"); is($t1, $t, "same threshold object after \$t->set_thresholds"); ok( defined $t, "Threshold ('0:45', '0:90') set"); is( $t->warning->start, 0, "Warning start ok"); is( $t->warning->end, 45, "Warning end ok"); is( $t->critical->start, 0, "Critical start ok"); is( $t->critical->end, 90, "Critical end ok"); # Also as of 0.16, accepts N::P::Range objects as arguments my $warning = Monitoring::Plugin::Range->parse_range_string("50"); my $critical = Monitoring::Plugin::Range->parse_range_string("70:90"); $t = Monitoring::Plugin::Threshold->set_thresholds(warning => $warning, critical => $critical); ok( defined $t, "Threshold from ranges ('50', '70:90') set"); is( $t->warning->start, 0, "Warning start ok"); is( $t->warning->end, 50, "Warning end ok"); is( $t->critical->start, 70, "Critical start ok"); is( $t->critical->end, 90, "Critical end ok"); $critical = Monitoring::Plugin::Range->parse_range_string("90:"); $t->set_thresholds(warning => "~:20", critical => $critical); ok( defined $t, "Threshold from string + range ('~:20', '90:') set"); ok( $t->warning->start_infinity, "Warning start ok (infinity)"); is( $t->warning->end, 20, "Warning end ok"); is( $t->critical->start, 90, "Critical start ok"); ok( $t->critical->end_infinity, "Critical end ok (infinity)"); ok 1, "sweet, made it to the end."; Monitoring-Plugin-0.40/t/Monitoring-Plugin-Getopt-03.t0000644000175000017500000000570712447775353021251 0ustar svensven# Monitoring::Plugin::Getopt --extra-opts tests use strict; use File::Spec; use File::Basename; use IO::File; use Test::More qw(no_plan); BEGIN { use_ok('Monitoring::Plugin::Getopt') }; # Needed to get evals to work in testing Monitoring::Plugin::Functions::_use_die(1); my $tdir = 'npg03'; if (! -d $tdir) { my $ttdir = File::Spec->catdir('t', $tdir); die "missing '$tdir' directory\n" unless -d $ttdir; $tdir = $ttdir; } # Load expected files my %EXPECTED = (); for my $efile (glob File::Spec->catfile($tdir, 'expected', '*')) { my $fh = IO::File->new($efile, 'r') or die "Cannot open input file '$efile': $!"; if (my $cmd = $fh->getline()) { # First line only! chomp $cmd; $cmd =~ s/^\s+//; $cmd =~ s/\s+$//; $EXPECTED{ basename($efile) } = $cmd; } } # Override MONITORING_CONFIG_PATH to use our test plugins.ini file $ENV{MONITORING_CONFIG_PATH} = "/random/bogus/path:$tdir"; my %PARAM = ( version => '0.01', blurb => 'This plugin tests various stuff.', usage => "Usage: %s -H -w -c ", ); sub ng_setup { my $arg = shift; # Instantiate object my $ng = Monitoring::Plugin::Getopt->new(%PARAM); if (ref $arg eq 'ARRAY' && @$arg) { $ng->arg(%$_) foreach @$arg; } return $ng; } # Setup our Monitoring::Plugin::Getopt object my $ng; my $arg = [ { spec => 'S', help => '-S' }, { spec => 'H=s', help => '-H' }, { spec => 'p=s@', help => '-p' }, { spec => 'path=s@', help => '--path' }, { spec => 'username|u=s', help => '--username' }, { spec => 'password=s', help => '--password' }, { spec => 'critical=s', help => '--critical' }, { spec => 'warning=s', help => '--warning' }, { spec => 'expect=s', help => '--expect' }, { spec => 'units=s', help => '--units' }, ]; #my %SKIP = map { $_ => 1 } qw(05_singlechar1 07_singlechar3); #my %SKIP = map { $_ => 1 } qw(06_singlechar2); my %SKIP = (); # Process all test cases in $tdir/input my $glob = $ARGV[0] || '*'; for my $infile (glob File::Spec->catfile($tdir, 'input', $glob)) { $ng = ng_setup($arg); my $fh = IO::File->new($infile, 'r') or die "Cannot open input file '$infile': $!"; $infile = basename($infile); if (my $cmd = $fh->getline()) { # First line only! $cmd =~ s/^\s+//; my ($plugin, @args) = split /\s+/, $cmd; # Fake out the plugin name $ng->{_attr}->{plugin} = $plugin; # Parse the options SKIP: { skip "Skipping ..." if $SKIP{$infile}; @ARGV = @args; eval { $ng->getopts }; if ($@) { chomp $@; ok($infile =~ m/_(dies?|catch)$/, "$infile ($@)"); my $expect = $EXPECTED{$infile}; # windows expects backslashes fixes rt.cpan #100708 $expect =~ s#/#\\#gmx if $^O =~ m/^MSWin/; is($@, $expect, $infile) if ($infile =~ m/_catch$/); } else { is($plugin . ' ' . $ng->_cmdline, $EXPECTED{$infile}, $infile); } } } } Monitoring-Plugin-0.40/t/check_stuff.pl0000755000175000017500000001025512267224147016627 0ustar svensven#!/usr/local/bin/perl ### check_stuff.pl # an example plugin using the Monitoring::Plugin module. # Originally by Nathan Vonnahme, n8v at users dot sourceforge # dot net, July 19 2006 # Please modify to your heart's content and use as the basis for all # the really cool monitoring scripts you're going to create. # You rock. ############################################################################## # prologue use strict; use warnings; use Monitoring::Plugin; 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 # https://www.monitoring-plugins.org/doc/guidelines.html#PLUGOPTIONS # Instantiate Monitoring::Plugin object (the 'usage' parameter is mandatory) my $p = Monitoring::Plugin->new( usage => "Usage: %s [ -v|--verbose ] [-H ] [-t ] [ -c|--critical= ] [ -w|--warning= ] [ -r|--result = ]", version => $VERSION, blurb => 'This plugin is an example of a monitoring plugin written in Perl using the Monitoring::Plugin modules. It will generate a random integer between 1 and 20 (though you can specify the number with the -n option for testing), and will output OK, WARNING or CRITICAL if the resulting number is outside the specified thresholds.', extra => " THRESHOLDs for -w and -c are specified 'min:max' or 'min:' or ':max' (or 'max'). If specified '\@min:max', a warning status will be generated if the count *is* inside the specified range. See more threshold examples at https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT Examples: $PROGNAME -w 10 -c 18 Returns a warning if the resulting number is greater than 10, or a critical error if it is greater than 18. $PROGNAME -w 10 : -c 4 : Returns a warning if the resulting number is less than 10, or a critical error if it is less than 4. " ); # Define and document the valid command line options # usage, help, version, timeout and verbose are defined by default. $p->add_arg( spec => 'warning|w=s', help => qq{-w, --warning=INTEGER:INTEGER Minimum and maximum number of allowable result, outside of which a warning will be generated. If omitted, no warning is generated.}, # required => 1, # default => 10, ); $p->add_arg( spec => 'critical|c=s', help => qq{-c, --critical=INTEGER:INTEGER Minimum and maximum number of the generated result, outside of which a critical will be generated. }, ); $p->add_arg( spec => 'result|r=f', help => qq{-r, --result=INTEGER Specify the result on the command line rather than generating a random number. For testing.}, ); # Parse arguments and process standard ones (e.g. usage, help, version) $p->getopts; # perform sanity checking on command line options if ( (defined $p->opts->result) && ($p->opts->result < 0 || $p->opts->result > 20) ) { $p->plugin_die( " invalid number supplied for the -r option " ); } unless ( defined $p->opts->warning || defined $p->opts->critical ) { $p->plugin_die( " you didn't supply a threshold argument " ); } ############################################################################## # check stuff. # THIS is where you'd do your actual checking to get a real value for $result # don't forget to timeout after $p->opts->timeout seconds, if applicable. my $result; if (defined $p->opts->result) { # you got a 'result' option from the command line options $result = $p->opts->result; print " using supplied result $result from command line \n " if $p->opts->verbose; } else { $result = int rand(20)+1; print " generated random result $result\n " if $p->opts->verbose; } ############################################################################## # check the result against the defined warning and critical thresholds, # output the result and exit $p->plugin_exit( return_code => $p->check_threshold($result), message => " sample result was $result" ); Monitoring-Plugin-0.40/t/Monitoring-Plugin-01.t0000644000175000017500000000370013076140206017754 0ustar svensven# Monitoring::Plugin original test cases use strict; use Test::More tests => 15; BEGIN { use_ok('Monitoring::Plugin') }; use Monitoring::Plugin::Functions; Monitoring::Plugin::Functions::_fake_exit(1); diag "\nusing Monitoring::Plugin revision ". $Monitoring::Plugin::VERSION . "\n" if $ENV{TEST_VERBOSE}; my $p = Monitoring::Plugin->new(); isa_ok( $p, "Monitoring::Plugin"); $p->shortname("PAGESIZE"); is($p->shortname, "PAGESIZE", "shortname explicitly set correctly"); $p = Monitoring::Plugin->new(); is($p->shortname, "MONITORING-PLUGIN-01", "shortname should default on new"); $p = Monitoring::Plugin->new( shortname => "SIZE", () ); is($p->shortname, "SIZE", "shortname set correctly on new"); $p = Monitoring::Plugin->new( plugin => "check_stuff", () ); is($p->shortname, "STUFF", "shortname uses plugin name as default"); $p = Monitoring::Plugin->new( shortname => "SIZE", plugin => "check_stuff", () ); is($p->shortname, "SIZE", "shortname is not overriden by default"); diag "warn if < 10, critical if > 25 " if $ENV{TEST_VERBOSE}; my $t = $p->set_thresholds( warning => "10:25", critical => "~:25" ); use Data::Dumper; #diag "dumping p: ". Dumper $p; #diag "dumping perfdata: ". Dumper $p->perfdata; $p->add_perfdata( label => "size", value => 1, uom => "kB", threshold => $t, ); cmp_ok( $p->all_perfoutput, 'eq', "size=1kB;10:25;~:25", "Perfdata correct"); #diag "dumping perfdata: ". Dumper ($p->perfdata); $p->add_perfdata( label => "time", value => "3.52", threshold => $t, ); is( $p->all_perfoutput, "size=1kB;10:25;~:25 time=3.52;10:25;~:25", "Perfdata correct when no uom specified"); my $expected = {qw( -1 WARNING 1 WARNING 20 OK 25 OK 26 CRITICAL 30 CRITICAL )}; foreach (sort {$a<=>$b} keys %$expected) { like $p->die( return_code => $t->get_status($_), message => "page size at http://... was ${_}kB" ), qr/$expected->{$_}/, "Output okay. $_ = $expected->{$_}" ; } Monitoring-Plugin-0.40/t/Monitoring-Plugin-04.t0000644000175000017500000000613512267053577020003 0ustar svensven # tests for toplevel access to Threshold and GetOpts stuff use strict; #use Test::More 'no_plan'; use Test::More tests=>30; BEGIN { use_ok('Monitoring::Plugin') }; use Monitoring::Plugin::Functions; Monitoring::Plugin::Functions::_fake_exit(1); eval { Monitoring::Plugin->new(); }; ok(! $@, "constructor DOESN'T die without usage"); my $p = Monitoring::Plugin->new(); eval { $p->add_arg('warning', 'warning') }; ok($@, "add_arg() dies if you haven't instantiated with usage"); eval { $p->getopts }; ok($@, "getopts() dies if you haven't instantiated with usage"); $p = Monitoring::Plugin->new( usage => "dummy usage statement" ); # option accessors work can_ok $p, 'opts'; isa_ok $p->opts, 'Monitoring::Plugin::Getopt', "Getopt object is defined"; $p->add_arg('warning|w=s', "warning"); $p->add_arg('critical|c=s', "critical"); @ARGV = qw(-w 5 -c 10); $p->getopts; is $p->opts->warning, "5", "warning opt is accessible"; is $p->opts->critical, "10", "critical opt is accessible"; can_ok $p, 'perfdata'; #isa_ok $p->perfdata, 'Monitoring::Plugin::Performance', "perfdata object is defined"; can_ok $p, 'threshold'; #isa_ok $p->threshold, 'Monitoring::Plugin::Threshold', "threshold object is defined"; eval { $p->check_threshold() }; ok($@, "check_threshold dies if called with no args"); # thresholds set implicitly is $p->check_threshold(2), OK, "check_threshold OK when called implicitly"; is $p->check_threshold(6), WARNING, "check_threshold WARNING"; is $p->check_threshold(11), CRITICAL, "check_threshold CRITICAL"; is $p->check_threshold(check=>11), CRITICAL, "check_threshold CRITICAL with hash param"; # Check that arrays allowed is $p->check_threshold([2,1]), OK, "check_threshold OK when called implicitly"; is $p->check_threshold([6,2]), WARNING, "check_threshold WARNING"; is $p->check_threshold([1,2,6,11]), CRITICAL, "check_threshold CRITICAL"; is $p->check_threshold(check=>[1,2,6,11]), CRITICAL, "check_threshold CRITICAL with hash param"; # thresholds set explicitly is $p->check_threshold( check => 2, warning => 50, critical => 100 ), OK, "check_threshold explicit OK"; is $p->check_threshold( check => 66, warning => 50, critical => 100 ), WARNING, "check_threshold explicit WARNING"; is $p->check_threshold( check => -1, warning => 5, critical => '0:5', ), CRITICAL, "check_threshold explicit CRITICAL"; # what happens if you forget to define warning or critical thresholds? $p = undef; $p = Monitoring::Plugin->new(); is $p->check_threshold(2), UNKNOWN, "everything is now UNKNOWN"; is $p->check_threshold(-200), UNKNOWN, "everything is now UNKNOWN"; is $p->check_threshold(134098.3124), UNKNOWN, "everything is now UNKNOWN"; is $p->check_threshold("foo bar baz"), UNKNOWN, "everything is now UNKNOWN"; # how about when you define just one? $p->set_thresholds(warning => "10:25"); is $p->check_threshold(2), WARNING, "check_threshold works (WARNING) after explicit set_thresholds"; is $p->check_threshold(-200), WARNING, "and again"; is $p->check_threshold(25.5), WARNING, "and again"; is $p->check_threshold(11), OK, "now OK"; Monitoring-Plugin-0.40/t/Monitoring-Plugin-02.t0000644000175000017500000001372212267062417017772 0ustar svensven# Monitoring::Plugin test set 2, testing MP::Functions wrapping use strict; use Test::More tests => 103; BEGIN { use_ok("Monitoring::Plugin") } require Monitoring::Plugin::Functions; Monitoring::Plugin::Functions::_fake_exit(1); # Hardcoded checks of constants my %ERRORS = %Monitoring::Plugin::Functions::ERRORS; is(OK, $ERRORS{OK}, "OK => $ERRORS{OK}"); is(WARNING, $ERRORS{WARNING}, "WARNING => $ERRORS{WARNING}"); is(CRITICAL, $ERRORS{CRITICAL}, "CRITICAL => $ERRORS{CRITICAL}"); is(UNKNOWN, $ERRORS{UNKNOWN}, "UNKNOWN => $ERRORS{UNKNOWN}"); is(DEPENDENT, $ERRORS{DEPENDENT}, "DEPENDENT => $ERRORS{DEPENDENT}"); my $plugin = 'TEST_PLUGIN'; my $np = Monitoring::Plugin->new( shortname => $plugin ); is($np->shortname, $plugin, "shortname() is $plugin"); # Test plugin_exit( CONSTANT, $msg ), plugin_exit( $string, $msg ) my $r; my @ok = ( [ OK, "OK", 'test the first', ], [ WARNING, "WARNING", 'test the second', ], [ CRITICAL, "CRITICAL", 'test the third', ], [ UNKNOWN, "UNKNOWN", 'test the fourth', ], [ DEPENDENT, "DEPENDENT", 'test the fifth', ], ); for (@ok) { # CONSTANT $r = $np->plugin_exit($_->[0], $_->[2]); is($r->return_code, $_->[0], sprintf('plugin_exit(%s, $msg) returned %s', $_->[1], $_->[0])); like($r->message, qr/$plugin\b.*$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_exit(%s, $msg) output matched "%s"', $_->[1], $plugin . ' ' . $_->[1] . '.*' . $_->[2])); # $string $r = $np->plugin_exit($_->[1], $_->[2]); is($r->return_code, $_->[0], sprintf('plugin_exit("%s", $msg) returned %s', $_->[1], $_->[0])); like($r->message, qr/$plugin\b.*$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_exit("%s", $msg) output matched "%s"', $_->[1], $plugin . ' ' . $_->[1] . '.*' . $_->[2])); like($r, qr/$plugin\b.*$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_exit("%s", $msg) stringified matched "%s"', $_->[1], $plugin . ' ' . $_->[1] . '.*' . $_->[2])); } # plugin_exit code corner cases my @ugly1 = ( [ -1, 'testing code -1' ], [ 7, 'testing code 7' ], [ undef, 'testing code undef' ], [ '', qq(testing code '') ], [ 'string', qq(testing code 'string') ], ); for (@ugly1) { $r = $np->plugin_exit($_->[0], $_->[1]); my $display = defined $_->[0] ? "'$_->[0]'" : 'undef'; is($r->return_code, UNKNOWN, "plugin_exit($display, \$msg) returned ". UNKNOWN); like($r->message, qr/UNKNOWN\b.*\b$_->[1]$/, sprintf('plugin_exit(%s, $msg) output matched "%s"', $display, 'UNKNOWN.*' . $_->[1])); } # plugin_exit message corner cases my @ugly2 = ( [ '' ], [ undef ], [ UNKNOWN ], ); for (@ugly2) { $r = $np->plugin_exit(CRITICAL, $_->[0]); my $display1 = defined $_->[0] ? "'$_->[0]'" : "undef"; my $display2 = defined $_->[0] ? $_->[0] : ''; like($r->message, qr/CRITICAL\b.*\b$display2$/, sprintf('plugin_exit(%s, $msg) output matched "%s"', $display1, "CRITICAL.*$display2")); } # Test plugin_die( $msg ) my @msg = ( [ 'die you dog' ], [ '' ], [ undef ], ); for (@msg) { $r = $np->plugin_die($_->[0]); my $display1 = defined $_->[0] ? "'$_->[0]'" : "undef"; my $display2 = defined $_->[0] ? $_->[0] : ''; is($r->return_code, UNKNOWN, sprintf('plugin_die(%s) returned UNKNOWN', $display1)); like($r->message, qr/UNKNOWN\b.*\b$display2$/, sprintf('plugin_die(%s) output matched "%s"', $display1, "UNKNOWN.*$display2")); } # Test plugin_die( CONSTANT, $msg ), plugin_die( $msg, CONSTANT ), # plugin_die( $string, $msg ), and plugin_die( $msg, $string ) @ok = ( [ OK, "OK", 'test the first', ], [ WARNING, "WARNING", 'test the second', ], [ CRITICAL, "CRITICAL", 'test the third', ], [ UNKNOWN, "UNKNOWN", 'test the fourth', ], [ DEPENDENT, "DEPENDENT", 'test the fifth', ], ); for (@ok) { # CONSTANT, $msg $r = $np->plugin_die($_->[0], $_->[2]); is($r->return_code, $_->[0], sprintf('plugin_die(%s, $msg) returned %s', $_->[1], $_->[0])); like($r->message, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_die(%s, $msg) output matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); # $msg, CONSTANT $r = $np->plugin_die($_->[2], $_->[0]); is($r->return_code, $_->[0], sprintf('plugin_die($msg, %s) returned %s', $_->[1], $_->[0])); like($r->message, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_die($msg, %s) output matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); # $string, $msg $r = $np->plugin_die($_->[1], $_->[2]); is($r->return_code, $_->[0], sprintf('plugin_die("%s", $msg) returned %s', $_->[1], $_->[0])); like($r->message, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_die("%s", $msg) output matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); like($r, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_die("%s", $msg) stringified matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); # $string, $msg $r = $np->plugin_die($_->[2], $_->[1]); is($r->return_code, $_->[0], sprintf('plugin_die($msg, "%s") returned %s', $_->[1], $_->[0])); like($r->message, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_die($msg, "%s") output matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); like($r, qr/$_->[1]\b.*\b$_->[2]$/, sprintf('plugin_die($msg, "%s") stringified matched "%s"', $_->[1], $_->[1] . '.*' . $_->[2])); } # shortname testing SKIP: { skip "requires File::Basename", 2 unless eval { require File::Basename }; $np = Monitoring::Plugin->new( version => "1"); $plugin = uc File::Basename::basename($0); $plugin =~ s/\..*$//; is($np->shortname, $plugin, "shortname() is '$plugin'"); $r = $np->plugin_exit(OK, "foobar"); like($r->message, qr/^$plugin OK/, "message begins with '$plugin OK'"); } Monitoring-Plugin-0.40/t/Monitoring-Plugin-03.t0000644000175000017500000002266712267062463020004 0ustar svensven# $np->check_messages tests use strict; use Test::More tests => 61; BEGIN { use_ok("Monitoring::Plugin"); use_ok("Monitoring::Plugin::Functions", ":all"); } Monitoring::Plugin::Functions::_fake_exit(1); my $plugin = 'MP_CHECK_MESSAGES_03'; my $np = Monitoring::Plugin->new( shortname => $plugin, () ); is($np->shortname, $plugin, "shortname() is $plugin"); my ($code, $message); # ------------------------------------------------------------------------- # Check codes my @codes = ( [ [ qw(Critical) ], [ qw(Warning) ], CRITICAL ], [ [], [ qw(Warning) ], WARNING ], [ [], [], OK ], ); my $i = 0; for (@codes) { $i++; $code = $np->check_messages( critical => $_->[0], warning => $_->[1] ); is($code, $_->[2], "Code test $i returned $STATUS_TEXT{$_->[2]}"); } # ------------------------------------------------------------------------- # Check messages my %arrays = ( critical => [ qw(A B C) ], warning => [ qw(D E F) ], ok => [ qw(G H I) ], ); my %messages = map { $_ => join(' ', @{$arrays{$_}}) } keys %arrays; # critical, warning ($code, $message) = $np->check_messages( critical => $arrays{critical}, warning => $arrays{warning}, ); is($code, CRITICAL, "(critical, warning) code is $STATUS_TEXT{$code}"); is($message, $messages{critical}, "(critical, warning) message is $message"); # critical, warning, ok ($code, $message) = $np->check_messages( critical => $arrays{critical}, warning => $arrays{warning}, ok => $arrays{ok}, ); is($code, CRITICAL, "(critical, warning, ok) code is $STATUS_TEXT{$code}"); is($message, $messages{critical}, "(critical, warning, ok) message is $message"); # critical, warning, $ok ($code, $message) = $np->check_messages( critical => $arrays{critical}, warning => $arrays{warning}, ok => 'G H I', ); is($code, CRITICAL, "(critical, warning, \$ok) code is $STATUS_TEXT{$code}"); is($message, $messages{critical}, "(critical, warning, \$ok) message is $message"); # warning ($code, $message) = $np->check_messages( critical => [], warning => $arrays{warning}, ); is($code, WARNING, "(warning) code is $STATUS_TEXT{$code}"); is($message, $messages{warning}, "(warning) message is $message"); # warning, ok ($code, $message) = $np->check_messages( critical => [], warning => $arrays{warning}, ok => $arrays{ok}, ); is($code, WARNING, "(warning, ok) code is $STATUS_TEXT{$code}"); is($message, $messages{warning}, "(warning, ok) message is $message"); # ok ($code, $message) = $np->check_messages( critical => [], warning => [], ok => $arrays{ok}, ); is($code, OK, "(ok) code is $STATUS_TEXT{$code}"); is($message, $messages{ok}, "(ok) message is $message"); # $ok ($code, $message) = $np->check_messages( critical => [], warning => [], ok => 'G H I', ); is($code, OK, "(\$ok) code is $STATUS_TEXT{$code}"); is($message, $messages{ok}, "(\$ok) message is $message"); # ------------------------------------------------------------------------- # explicit join my $join = '+'; ($code, $message) = $np->check_messages( critical => $arrays{critical}, warning => $arrays{warning}, join => $join, ); is($message, join($join, @{$arrays{critical}}), "joined '$join' (critical, warning) message is $message"); $join = ''; ($code, $message) = $np->check_messages( critical => [], warning => $arrays{warning}, join => $join, ); is($message, join($join, @{$arrays{warning}}), "joined '$join' (warning) message is $message"); $join = undef; ($code, $message) = $np->check_messages( critical => [], warning => [], ok => $arrays{ok}, join => $join, ); is($message, join(' ', @{$arrays{ok}}), "joined undef (ok) message is $message"); # ------------------------------------------------------------------------- # join_all messages my $join_all = ' :: '; my $msg_all_cwo = join($join_all, map { join(' ', @{$arrays{$_}}) } qw(critical warning ok)); my $msg_all_cw = join($join_all, map { join(' ', @{$arrays{$_}}) } qw(critical warning)); my $msg_all_wo = join($join_all, map { join(' ', @{$arrays{$_}}) } qw(warning ok)); # critical, warning, ok ($code, $message) = $np->check_messages( critical => $arrays{critical}, warning => $arrays{warning}, ok => $arrays{ok}, join_all => $join_all, ); is($code, CRITICAL, "(critical, warning, ok) code is $STATUS_TEXT{$code}"); is($message, $msg_all_cwo, "join_all '$join_all' (critical, warning, ok) message is $message"); # critical, warning, $ok ($code, $message) = $np->check_messages( critical => $arrays{critical}, warning => $arrays{warning}, ok => 'G H I', join_all => $join_all, ); is($code, CRITICAL, "(critical, warning, \$ok) code is $STATUS_TEXT{$code}"); is($message, $msg_all_cwo, "join_all '$join_all' (critical, warning, \$ok) message is $message"); # critical, warning ($code, $message) = $np->check_messages( critical => $arrays{critical}, warning => $arrays{warning}, join_all => $join_all, ); is($code, CRITICAL, "(critical, warning) code is $STATUS_TEXT{$code}"); is($message, $msg_all_cw, "join_all '$join_all' (critical, warning) message is $message"); # warning, ok ($code, $message) = $np->check_messages( critical => [], warning => $arrays{warning}, ok => $arrays{ok}, join_all => $join_all, ); is($code, WARNING, "(warning, ok) code is $STATUS_TEXT{$code}"); is($message, $msg_all_wo, "join_all '$join_all' (critical, warning, ok) message is $message"); # warning, $ok ($code, $message) = $np->check_messages( critical => [], warning => $arrays{warning}, ok => 'G H I', join_all => $join_all, ); is($code, WARNING, "(warning, \$ok) code is $STATUS_TEXT{$code}"); is($message, $msg_all_wo, "join_all '$join_all' (critical, warning, \$ok) message is $message"); # warning ($code, $message) = $np->check_messages( critical => [], warning => $arrays{warning}, join_all => $join_all, ); is($code, WARNING, "(warning) code is $STATUS_TEXT{$code}"); is($message, 'D E F', "join_all '$join_all' (critical, warning) message is $message"); # ------------------------------------------------------------------------- # add_messages # Constant codes $np = Monitoring::Plugin->new(); $np->add_message( CRITICAL, "A B C" ); $np->add_message( WARNING, "D E F" ); ($code, $message) = $np->check_messages(); is($code, CRITICAL, "(CRITICAL, WARNING) code is $STATUS_TEXT{$code}"); is($message, $messages{critical}, "(CRITICAL, WARNING) message is $message"); $np = Monitoring::Plugin->new(); $np->add_message( CRITICAL, "A B C" ); ($code, $message) = $np->check_messages(); is($code, CRITICAL, "(CRITICAL) code is $STATUS_TEXT{$code}"); is($message, $messages{critical}, "(CRITICAL) message is $message"); $np = Monitoring::Plugin->new(); $np->add_message( WARNING, "D E F" ); ($code, $message) = $np->check_messages(); is($code, WARNING, "(WARNING) code is $STATUS_TEXT{$code}"); is($message, $messages{warning}, "(WARNING) message is $message"); $np = Monitoring::Plugin->new(); $np->add_message( WARNING, "D E F" ); $np->add_message( OK, "G H I" ); ($code, $message) = $np->check_messages(); is($code, WARNING, "(WARNING, OK) code is $STATUS_TEXT{$code}"); is($message, $messages{warning}, "(WARNING, OK) message is $message"); $np = Monitoring::Plugin->new(); $np->add_message( OK, "G H I" ); ($code, $message) = $np->check_messages(); is($code, OK, "(OK) code is $STATUS_TEXT{$code}"); is($message, $messages{ok}, "(OK) message is $message"); # String codes $np = Monitoring::Plugin->new(); $np->add_message( critical => "A B C" ); $np->add_message( warning => "D E F" ); ($code, $message) = $np->check_messages(); is($code, CRITICAL, "(critical, warning) code is $STATUS_TEXT{$code}"); is($message, $messages{critical}, "(critical, warning) message is $message"); $np = Monitoring::Plugin->new(); $np->add_message( critical => "A B C" ); ($code, $message) = $np->check_messages(); is($code, CRITICAL, "(critical) code is $STATUS_TEXT{$code}"); is($message, $messages{critical}, "(critical) message is $message"); $np = Monitoring::Plugin->new(); $np->add_message( warning => "D E F" ); ($code, $message) = $np->check_messages(); is($code, WARNING, "(warning) code is $STATUS_TEXT{$code}"); is($message, $messages{warning}, "(warning) message is $message"); $np = Monitoring::Plugin->new(); $np->add_message( warning => "D E F" ); $np->add_message( ok => "G H I" ); ($code, $message) = $np->check_messages(); is($code, WARNING, "(warning, ok) code is $STATUS_TEXT{$code}"); is($message, $messages{warning}, "(warning, ok) message is $message"); $np = Monitoring::Plugin->new(); $np->add_message( ok => "G H I" ); ($code, $message) = $np->check_messages(); is($code, OK, "(ok) code is $STATUS_TEXT{$code}"); is($message, $messages{ok}, "(ok) message is $message"); # No add_message $np = Monitoring::Plugin->new(); ($code, $message) = $np->check_messages(); is($code, OK, "() code is $STATUS_TEXT{$code}"); is($message, '', "() message is ''"); # ------------------------------------------------------------------------- # Error conditions # add_message errors $np = Monitoring::Plugin->new(); ok(! defined eval { $np->add_message( foobar => 'hi mum' ) }, 'add_message dies on invalid code'); ok(! defined eval { $np->add_message( OKAY => 'hi mum' ) }, 'add_message dies on invalid code'); # UNKNOWN and DEPENDENT error codes ok(! defined eval { $np->add_message( unknown => 'hi mum' ) }, 'add_message dies on UNKNOWN code'); ok(! defined eval { $np->add_message( dependent => 'hi mum' ) }, 'add_message dies on DEPENDENT code'); Monitoring-Plugin-0.40/t/Monitoring-Plugin-Performance.t0000644000175000017500000004021712267054147022012 0ustar svensven use warnings; use strict; use Test::More; use Monitoring::Plugin::Functions; Monitoring::Plugin::Functions::_fake_exit(1); my (@p, $p); my @test = ( { perfoutput => "/=382MB;15264;15269;0;32768", label => '/', rrdlabel => 'root', value => 382, uom => 'MB', warning => 15264, critical => 15269, min => 0, max => 32768, clean_label => "root", }, { perfoutput => "/var=218MB;9443;9448", label => '/var', rrdlabel => 'var', value => '218', uom => 'MB', warning => 9443, critical => 9448, min => undef, max => undef, clean_label => "var", }, { perfoutput => '/var/long@:-/filesystem/name/and/bad/chars=218MB;9443;9448', label => '/var/long@:-/filesystem/name/and/bad/chars', rrdlabel => 'var_long____filesys', value => '218', uom => 'MB', warning => 9443, critical => 9448, min => undef, max => undef, clean_label => 'var_long____filesystem_name_and_bad_chars', }, { perfoutput => "'page file'=36%;80;90;", expected_perfoutput => "'page file'=36%;80;90", label => 'page file', rrdlabel => 'page_file', value => '36', uom => '%', warning => 80, critical => 90, min => undef, max => undef, clean_label => 'page_file', }, { perfoutput => "'data'=5;;;;", expected_perfoutput => "data=5;;", label => 'data', rrdlabel => 'data', value => 5, uom => "", warning => undef, critical => undef, min => undef, max => undef, clean_label => 'data', }, ); plan tests => (11 * scalar @test) + 176; use_ok('Monitoring::Plugin::Performance'); diag "\nusing Monitoring::Plugin::Performance revision ". $Monitoring::Plugin::Performance::VERSION . "\n" if $ENV{TEST_VERBOSE}; # Round-trip tests for my $t (@test) { # Parse to components ($p) = Monitoring::Plugin::Performance->parse_perfstring($t->{perfoutput}); is ($p->value, $t->{value}, "value okay $t->{value}"); is ($p->label, $t->{label}, "label okay $t->{label}"); is ($p->uom, $t->{uom}, "uom okay $t->{uom}"); # Construct from components my @construct = qw(label value uom warning critical min max); $p = Monitoring::Plugin::Performance->new(map { $_ => $t->{$_} } @construct); my $expected_perfoutput = $t->{perfoutput}; if (exists $t->{expected_perfoutput}) { $expected_perfoutput = $t->{expected_perfoutput}; }; is($p->perfoutput, $expected_perfoutput, "perfoutput okay ($expected_perfoutput)"); # Check threshold accessor foreach my $type (qw(warning critical)) { if (! defined $t->{$type}) { isnt( $p->threshold->$type->is_set, "threshold $type not set"); } else { is($p->threshold->$type->end, $t->{$type}, "threshold $type okay ($t->{$type})"); } } is($p->rrdlabel, $t->{rrdlabel}, "rrdlabel okay"); is($p->clean_label, $t->{clean_label}, "clean_label okay" ); # Construct using threshold @construct = qw(label value uom min max); $p = Monitoring::Plugin::Performance->new( map({ $_ => $t->{$_} } @construct), threshold => Monitoring::Plugin::Threshold->set_thresholds(warning => $t->{warning}, critical => $t->{critical}), ); is($p->perfoutput, $expected_perfoutput, "perfoutput okay ($expected_perfoutput)"); # Check warning/critical accessors foreach my $type (qw(warning critical)) { if (! defined $t->{$type}) { isnt( $p->threshold->$type->is_set, "threshold $type not set"); } else { is($p->threshold->$type->end, $t->{$type}, "threshold $type okay ($t->{$type})"); } } } # Test multiple parse_perfstrings @p = Monitoring::Plugin::Performance->parse_perfstring("/=382MB;15264;15269;; /var=218MB;9443;9448"); cmp_ok( $p[0]->label, 'eq', "/", "label okay"); cmp_ok( $p[0]->rrdlabel, 'eq', "root", "rrd label okay"); cmp_ok( $p[0]->value, '==', 382, "value okay"); cmp_ok( $p[0]->uom, 'eq', "MB", "uom okay"); cmp_ok( $p[0]->threshold->warning->end, "==", 15264, "warn okay"); cmp_ok( $p[0]->threshold->critical->end, "==", 15269, "crit okay"); ok(! defined $p[0]->min, "min undef"); ok(! defined $p[0]->max, "max undef"); cmp_ok( $p[1]->label, 'eq', "/var", "label okay"); cmp_ok( $p[1]->rrdlabel, 'eq', "var", "rrd label okay"); cmp_ok( $p[1]->value, '==', 218, "value okay"); cmp_ok( $p[1]->uom, 'eq', "MB", "uom okay"); cmp_ok( $p[1]->threshold->warning->end, "==", 9443, "warn okay"); cmp_ok( $p[1]->threshold->critical->end, "==", 9448, "crit okay"); @p = Monitoring::Plugin::Performance->parse_perfstring("rubbish"); ok( ! @p, "Errors correctly"); ok( ! Monitoring::Plugin::Performance->parse_perfstring(""), "Errors on empty string"); # Check 1 bad with 1 good format output @p = Monitoring::Plugin::Performance->parse_perfstring("rta=&391ms;100,200;500,034;0; pl=0%;20;60 "); is( scalar @p, 1, "One bad piece of data - only one returned" ); is( $p[0]->label, "pl", "label okay for different numeric"); is( $p[0]->value, 0, "value okay"); is( $p[0]->uom, "%", "uom okay"); ok( $p[0]->threshold->warning->is_set, "Warning range has been set"); is( $p[0]->threshold->warning, "20", "warn okay"); is( $p[0]->threshold->critical->is_set, 1, "Critical range has been set"); is( $p[0]->threshold->critical, "60", "warn okay"); # Same as above, but order swapped @p = Monitoring::Plugin::Performance->parse_perfstring(" pl=0%;20;60 rta=&391ms;100,200;500,034;0; "); is( scalar @p, 1, "One bad piece of data - only one returned" ); is( $p[0]->label, "pl", "label okay for different numeric"); is( $p[0]->value, 0, "value okay"); is( $p[0]->uom, "%", "uom okay"); ok( $p[0]->threshold->warning->is_set, "Warning range has been set"); is( $p[0]->threshold->warning, "20", "warn okay"); is( $p[0]->threshold->critical->is_set, 1, "Critical range has been set"); is( $p[0]->threshold->critical, "60", "warn okay"); @p = Monitoring::Plugin::Performance->parse_perfstring( "time=0.001229s;0.000000;0.000000;0.000000;10.000000"); cmp_ok( $p[0]->label, "eq", "time", "label okay"); cmp_ok( $p[0]->value, "==", 0.001229, "value okay"); cmp_ok( $p[0]->uom, "eq", "s", "uom okay"); ok( $p[0]->threshold->warning->is_set, "warn okay"); ok( $p[0]->threshold->critical->is_set, "crit okay"); @p = Monitoring::Plugin::Performance->parse_perfstring( "load1=0.000;5.000;9.000;0; load5=0.000;5.000;9.000;0; load15=0.000;5.000;9.000;0;"); cmp_ok( $p[0]->label, "eq", "load1", "label okay"); cmp_ok( $p[0]->value, "eq", "0", "value okay with 0 as string"); cmp_ok( $p[0]->uom, "eq", "", "uom empty"); cmp_ok( $p[0]->threshold->warning, "eq", "5", "warn okay"); cmp_ok( $p[0]->threshold->critical, "eq", "9", "crit okay"); cmp_ok( $p[1]->label, "eq", "load5", "label okay"); cmp_ok( $p[2]->label, "eq", "load15", "label okay"); @p = Monitoring::Plugin::Performance->parse_perfstring( "users=4;20;50;0" ); cmp_ok( $p[0]->label, "eq", "users", "label okay"); cmp_ok( $p[0]->value, "==", 4, "value okay"); cmp_ok( $p[0]->uom, "eq", "", "uom empty"); cmp_ok( $p[0]->threshold->warning, 'eq', "20", "warn okay"); cmp_ok( $p[0]->threshold->critical, 'eq', "50", "crit okay"); @p = Monitoring::Plugin::Performance->parse_perfstring( "users=4;20;50;0\n" ); ok( @p, "parse correctly with linefeed at end (nagiosgraph)"); @p = Monitoring::Plugin::Performance->parse_perfstring( "time=0.215300s;5.000000;10.000000;0.000000 size=426B;;;0" ); cmp_ok( $p[0]->label, "eq", "time", "label okay"); cmp_ok( $p[0]->value, "eq", "0.2153", "value okay"); cmp_ok( $p[0]->uom, "eq", "s", "uom okay"); cmp_ok( $p[0]->threshold->warning, 'eq', "5", "warn okay"); cmp_ok( $p[0]->threshold->critical, 'eq', "10", "crit okay"); cmp_ok( $p[1]->label, "eq", "size", "label okay"); cmp_ok( $p[1]->value, "==", 426, "value okay"); cmp_ok( $p[1]->uom, "eq", "B", "uom okay"); ok( ! $p[1]->threshold->warning->is_set, "warn okay"); ok( ! $p[1]->threshold->critical->is_set, "crit okay"); # Edge cases @p = Monitoring::Plugin::Performance->parse_perfstring("/home/a-m=0;0;0 shared-folder:big=20 12345678901234567890=20"); cmp_ok( $p[0]->rrdlabel, "eq", "home_a_m", "changing / to _"); ok( $p[0]->threshold->warning->is_set, "Warning range has been set"); cmp_ok( $p[1]->rrdlabel, "eq", "shared_folder_big", "replacing bad characters"); cmp_ok( $p[2]->rrdlabel, "eq", "1234567890123456789", "shortening rrd label"); # turn off fake_exit and enable use_die so we pick up on errors via plugin_die Monitoring::Plugin::Functions::_use_die(1); Monitoring::Plugin::Functions::_fake_exit(0); @p = Monitoring::Plugin::Performance->parse_perfstring("time=0.002722s;0.000000;0.000000;0.000000;10.000000"); cmp_ok( $p[0]->label, "eq", "time", "label okay"); cmp_ok( $p[0]->value, "eq", "0.002722", "value okay"); cmp_ok( $p[0]->uom, "eq", "s", "uom okay"); ok( defined $p[0]->threshold->warning->is_set, "Warning range has been set"); ok( defined $p[0]->threshold->critical->is_set, "Critical range has been set"); # The two below used to be cmp_ok, but Test::More 0.86 appears to have a problem with a stringification # of 0. See http://rt.cpan.org/Ticket/Display.html?id=41109 # We need to force stringification for test. See RT 57709 is( $p[0]->threshold->warning."", "0", "warn okay"); is( $p[0]->threshold->critical."", "0", "crit okay"); @p = Monitoring::Plugin::Performance->parse_perfstring("pct_used=73.7%;90;95"); cmp_ok( $p[0]->label, "eq", "pct_used", "label okay"); cmp_ok( $p[0]->value, "eq", "73.7", "value okay"); cmp_ok( $p[0]->uom, "eq", "%", "uom okay"); ok( defined eval { $p[0]->threshold->warning->is_set }, "Warning range has been set"); ok( defined eval { $p[0]->threshold->critical->is_set }, "Critical range has been set"); cmp_ok( $p[0]->threshold->warning, 'eq', "90", "warn okay"); cmp_ok( $p[0]->threshold->critical, 'eq', "95", "crit okay"); # Check ranges are parsed correctly @p = Monitoring::Plugin::Performance->parse_perfstring("availability=93.8%;90:99;"); is( $p[0]->label, "availability", "label okay"); is( $p[0]->value, "93.8", "value okay"); is( $p[0]->uom, "%", "uom okay"); ok( defined eval { $p[0]->threshold->warning->is_set }, "Warning range has been set"); is( $p[0]->threshold->critical->is_set, 0, "Critical range has not been set"); is( $p[0]->threshold->warning, "90:99", "warn okay"); # Check that negative values are parsed correctly in value and ranges @p = Monitoring::Plugin::Performance->parse_perfstring("offset=-0.004476s;-60.000000:-5;-120.000000:-3;"); is( $p[0]->label, "offset", "label okay"); is( $p[0]->value, "-0.004476", "value okay"); is( $p[0]->uom, "s", "uom okay"); ok( defined eval { $p[0]->threshold->warning->is_set }, "Warning range has been set"); ok( defined eval { $p[0]->threshold->critical->is_set }, "Critical range has been set"); is( $p[0]->threshold->warning, "-60:-5", "warn okay"); is( $p[0]->threshold->critical, "-120:-3", "crit okay"); # Check infinity values are okay @p = Monitoring::Plugin::Performance->parse_perfstring("salary=52GBP;~:23.5;45.2:"); is( $p[0]->label, "salary", "label okay"); is( $p[0]->value, "52", "value okay"); is( $p[0]->uom, "GBP", "uom okay"); ok( defined eval { $p[0]->threshold->warning->is_set }, "Warning range has been set"); is( $p[0]->threshold->critical->is_set, 1, "Critical range has been set"); is( $p[0]->threshold->warning, "~:23.5", "warn okay"); is( $p[0]->threshold->critical, "45.2:", "warn okay"); # Check scientific notation @p = Monitoring::Plugin::Performance->parse_perfstring("offset=1.120567322e-05"); is( $p[0]->label, "offset", "label okay for scientific notation"); is( $p[0]->value, 1.120567322e-05, "value okay"); is( $p[0]->uom, "", "uom okay"); ok( ! $p[0]->threshold->warning->is_set, "Warning range has not been set"); ok( ! $p[0]->threshold->critical->is_set, "Critical range has not been set"); # Check scientific notation with warnings and criticals @p = Monitoring::Plugin::Performance->parse_perfstring("offset=-1.120567322e-05unit;-1.1e-05:1.0e-03;4.3e+02:4.3e+25"); is( $p[0]->label, "offset", "label okay for scientific notation in warnings and criticals"); is( $p[0]->value, -1.120567322e-05, "value okay"); is( $p[0]->uom, "unit", "uom okay"); ok( $p[0]->threshold->warning->is_set, "Warning range has been set"); is( $p[0]->threshold->warning, "-1.1e-05:0.001", "warn okay"); is( $p[0]->threshold->critical->is_set, 1, "Critical range has been set"); is( $p[0]->threshold->critical, "430:4.3e+25", "warn okay"); # Check different collation with commas instead of periods @p = Monitoring::Plugin::Performance->parse_perfstring("rta=1,391ms;100,200;500,034;0; pl=0%;20;60;;"); is( $p[0]->label, "rta", "label okay for numeric with commas instead of periods"); is( $p[0]->value, 1.391, "value okay"); is( $p[0]->uom, "ms", "uom okay"); ok( $p[0]->threshold->warning->is_set, "Warning range has been set"); is( $p[0]->threshold->warning, "100.2", "warn okay"); is( $p[0]->threshold->critical->is_set, 1, "Critical range has been set"); is( $p[0]->threshold->critical, "500.034", "warn okay"); is( $p[1]->label, "pl", "label okay for different numeric"); is( $p[1]->value, 0, "value okay"); is( $p[1]->uom, "%", "uom okay"); ok( $p[1]->threshold->warning->is_set, "Warning range has been set"); is( $p[1]->threshold->warning, "20", "warn okay"); is( $p[1]->threshold->critical->is_set, 1, "Critical range has been set"); is( $p[1]->threshold->critical, "60", "warn okay"); # Another set of comma separated stuff @p = Monitoring::Plugin::Performance->parse_perfstring("offset=-0,023545s;60,000000;120,000000;"); is( $p[0]->label, "offset", "label okay for numeric with commas instead of periods"); is( $p[0]->value, -0.023545, "value okay"); is( $p[0]->uom, "s", "uom okay"); is( $p[0]->threshold->warning->is_set, 1, "Warning range has been set"); is( $p[0]->threshold->warning, 60, "warn okay"); is( $p[0]->threshold->critical->is_set, 1, "Critical range has been set"); is( $p[0]->threshold->critical, 120, "warn okay"); # Some values with funny commas @p = Monitoring::Plugin::Performance->parse_perfstring("time=1800,600,300,0,3600 other=45.6"); is( $p[0]->label, "other", "Ignored time=1800,600,300,0,3600, but allowed other=45.6"); is( $p[0]->value, 45.6, "value okay"); is( $p[0]->uom, "", "uom okay"); # Test labels with spaces (returned by nsclient++) @p = Monitoring::Plugin::Performance->parse_perfstring("'C:\ Label: Serial Number bc22aa2e'=8015MB;16387;18435;0;20484 'D:\ Label: Serial Number XA22aa2e'=8015MB;16388;18436;1;2048"); is( $p[0]->label, "C:\ Label: Serial Number bc22aa2e"); is( $p[0]->rrdlabel, "C__Label___Serial_N"); is( $p[0]->value, 8015, "value okay"); is( $p[0]->uom, "MB", "uom okay"); is( $p[0]->threshold->warning->end, 16387, "warn okay"); is( $p[0]->threshold->critical->end, 18435, "crit okay"); is( $p[0]->min, 0, "min ok"); is( $p[0]->max, 20484, "max ok"); is( $p[1]->label, "D:\ Label: Serial Number XA22aa2e", "label okay"); is( $p[1]->rrdlabel, "D__Label__Serial_Nu", "rrd label okay"); is( $p[1]->value, 8015, "value okay"); is( $p[1]->uom, "MB", "uom okay"); is( $p[1]->threshold->warning->end, 16388, "warn okay"); is( $p[1]->threshold->critical->end, 18436, "crit okay"); is( $p[1]->min, 1, "min ok"); is( $p[1]->max, 2048, "max ok"); # Mix labels with and without quotes @p = Monitoring::Plugin::Performance->parse_perfstring(" short=4 'C:\ Label: Serial Number bc22aa2e'=8015MB;16387;18435;0;20484 end=5 "); is( $p[0]->label, "short" ); is( $p[0]->rrdlabel, "short"); is( $p[0]->value, 4, "value okay"); is( $p[0]->uom, "", "uom okay"); isnt( $p[0]->threshold->warning->is_set, "warn okay"); isnt( $p[0]->threshold->critical->is_set, "crit okay"); is( $p[0]->min, undef, "min ok"); is( $p[0]->max, undef, "max ok"); is( $p[1]->label, "C:\ Label: Serial Number bc22aa2e", "label okay"); is( $p[1]->rrdlabel, "C__Label___Serial_N", "rrd label okay"); is( $p[1]->value, 8015, "value okay"); is( $p[1]->uom, "MB", "uom okay"); is( $p[1]->threshold->warning->end, 16387, "warn okay"); is( $p[1]->threshold->critical->end, 18435, "crit okay"); is( $p[1]->min, 0, "min ok"); is( $p[1]->max, 20484, "max ok"); is( $p[2]->label, "end" ); is( $p[2]->rrdlabel, "end" ); is( $p[2]->value, 5, "value okay"); is( $p[2]->uom, "", "uom okay"); isnt( $p[2]->threshold->warning->is_set, "warn okay"); isnt( $p[2]->threshold->critical->is_set, 18436, "crit okay"); is( $p[2]->min, undef, "min ok"); is( $p[2]->max, undef, "max ok"); @p = Monitoring::Plugin::Performance->parse_perfstring("processes=9;WKFLSV32.exe;9="); is_deeply( \@p, [], "Fails parsing correctly"); # add_perfdata tests in t/Monitoring-Plugin-01.t Monitoring-Plugin-0.40/t/Monitoring-Plugin-Functions-03.t0000644000175000017500000000120112267053414021723 0ustar svensven# max_state tests use strict; use Test::More tests => 8; BEGIN { use_ok("Monitoring::Plugin::Functions", ":all") } my $new_state = max_state( OK, WARNING ); is( $new_state, WARNING, "Moved up to WARNING" ); is( max_state( $new_state, UNKNOWN ), WARNING, "Still at WARNING" ); $new_state = max_state( $new_state, CRITICAL ); is( $new_state, CRITICAL, "Now at CRITICAL" ); is( max_state( OK, OK ), OK, "This is OK" ); is( max_state( OK, UNKNOWN ), OK, "This is still OK, not UNKNOWN" ); is( max_state( OK, OK, OK, OK, OK, WARNING ), WARNING, "Use WARNING in this list" ); is( max_state(), UNKNOWN, "Return UNKNOWN if no parameters" ); Monitoring-Plugin-0.40/lib/0000755000175000017500000000000013326155245014302 5ustar svensvenMonitoring-Plugin-0.40/lib/Monitoring/0000755000175000017500000000000013326155245016427 5ustar svensvenMonitoring-Plugin-0.40/lib/Monitoring/Plugin/0000755000175000017500000000000013326155245017665 5ustar svensvenMonitoring-Plugin-0.40/lib/Monitoring/Plugin/ExitResult.pm0000644000175000017500000000333412267223727022342 0ustar svensvenpackage Monitoring::Plugin::ExitResult; # Tiny helper class to return both output and return_code when testing use 5.006; use strict; use warnings; # Stringify to message use overload '""' => sub { shift->{message} }; # Constructor sub new { my $class = shift; return bless { return_code => $_[0], message => $_[1] }, $class; } # Accessors sub message { shift->{message} } sub return_code { shift->{return_code} } sub code { shift->{return_code} } 1; __END__ =head1 NAME Monitoring::Plugin::ExitResult - Helper class for returning both output and return codes when testing. =head1 SYNOPSIS use Test::More; use Monitoring::Plugin::Functions; # In a test file somewhere Monitoring::Plugin::Functions::_fake_exit(1); # Later ... $e = plugin_exit( CRITICAL, 'aiiii ...' ); print $e->message; print $e->return_code; # MP::ExitResult also stringifies to the message output like(plugin_exit( WARNING, 'foobar'), qr/^foo/, 'matches!'); =head1 DESCRIPTION Monitoring::Plugin::ExitResult is a tiny helper class intended for use when testing other Monitoring::Plugin modules. A Monitoring::Plugin::ExitResult object is returned by plugin_exit() and friends when Monitoring::Plugin::Functions::_fake_exit has been set, instead of doing a conventional print + exit. =head1 AUTHOR This code is maintained by the Monitoring Plugin Development Team: see https://monitoring-plugins.org Originally: Gavin Carr , Egavin@openfusion.com.auE =head1 COPYRIGHT AND LICENSE Copyright (C) 2014 by Monitoring Plugin Team Copyright (C) 2006-2014 by Nagios Plugin Development Team This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Monitoring-Plugin-0.40/lib/Monitoring/Plugin/Range.pm0000644000175000017500000001012513203014713021242 0ustar svensvenpackage Monitoring::Plugin::Range; use 5.006; use strict; use warnings; use Carp; use base qw(Class::Accessor::Fast); __PACKAGE__->mk_accessors( qw(start end start_infinity end_infinity alert_on) ); use Monitoring::Plugin::Functions qw(:DEFAULT $value_re); our ($VERSION) = $Monitoring::Plugin::Functions::VERSION; use overload 'eq' => sub { shift->_stringify }, '""' => sub { shift->_stringify }; # alert_on constants (undef == range not set) use constant OUTSIDE => 0; use constant INSIDE => 1; sub _stringify { my $self = shift; return "" unless $self->is_set; return (($self->alert_on) ? "@" : "") . (($self->start_infinity == 1) ? "~:" : (($self->start == 0)?"":$self->start.":")) . (($self->end_infinity == 1) ? "" : $self->end); } sub is_set { my $self = shift; (! defined $self->alert_on) ? 0 : 1; } sub _set_range_start { my ($self, $value) = @_; $self->start($value+0); # Force scalar into number $self->start_infinity(0); } sub _set_range_end { my ($self, $value) = @_; $self->end($value+0); # Force scalar into number $self->end_infinity(0); } # Returns a N::P::Range object if the string is a conforms to a Monitoring Plugin range string, otherwise null sub parse_range_string { my ($class, $string) = @_; my $valid = 0; my $range = $class->new( start => 0, start_infinity => 0, end => 0, end_infinity => 1, alert_on => OUTSIDE); $string =~ s/\s//g; # strip out any whitespace # check for valid range definition unless ( $string =~ /[\d~]/ && $string =~ m/^\@?($value_re|~)?(:($value_re)?)?$/ ) { carp "invalid range definition '$string'"; return undef; } if ($string =~ s/^\@//) { $range->alert_on(INSIDE); } if ($string =~ s/^~//) { # '~:x' $range->start_infinity(1); } if ( $string =~ m/^($value_re)?:/ ) { # '10:' my $start = $1; $range->_set_range_start($start) if defined $start; $range->end_infinity(1); # overridden below if there's an end specified $string =~ s/^($value_re)?://; $valid++; } if ($string =~ /^($value_re)$/) { # 'x:10' or '10' $range->_set_range_end($string); $valid++; } if ($valid && ($range->start_infinity == 1 || $range->end_infinity == 1 || $range->start <= $range->end)) { return $range; } return undef; } # Returns 1 if an alert should be raised, otherwise 0 sub check_range { my ($self, $value) = @_; my $false = 0; my $true = 1; if ($self->alert_on == INSIDE) { $false = 1; $true = 0; } if ($self->end_infinity == 0 && $self->start_infinity == 0) { if ($self->start <= $value && $value <= $self->end) { return $false; } else { return $true; } } elsif ($self->start_infinity == 0 && $self->end_infinity == 1) { if ( $value >= $self->start ) { return $false; } else { return $true; } } elsif ($self->start_infinity == 1 && $self->end_infinity == 0) { if ($value <= $self->end) { return $false; } else { return $true; } } else { return $false; } } # Constructor - map args to hashref for SUPER sub new { shift->SUPER::new({ @_ }); } 1; __END__ =head1 NAME Monitoring::Plugin::Range - class for handling Monitoring::Plugin range data. =head1 SYNOPSIS # NB: This is an internal Monitoring::Plugin class. # See Monitoring::Plugin itself for public interfaces. # Instantiate an empty range object $r = Monitoring::Plugin::Range->new; # Instantiate by parsing a standard nagios range string $r = Monitoring::Plugin::Range->parse_range_string( $range_str ); # Returns true if the range is defined/non-empty $r->is_set; # Returns true if $value matches range, false otherwise $r->check_range($value); =head1 DESCRIPTION Internal Monitoring::Plugin class for handling common range data. See Monitoring::Plugin for public interfaces. =head1 AUTHOR This code is maintained by the Monitoring Plugin Development Team: see https://monitoring-plugins.org =head1 COPYRIGHT AND LICENSE Copyright (C) 2014 by Monitoring Plugin Team Copyright (C) 2006-2014 by Nagios Plugin Development Team This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Monitoring-Plugin-0.40/lib/Monitoring/Plugin/Threshold.pm0000644000175000017500000000630012267223661022157 0ustar svensvenpackage Monitoring::Plugin::Threshold; use 5.006; use strict; use warnings; use base qw(Class::Accessor::Fast); __PACKAGE__->mk_accessors(qw(warning critical)); use Monitoring::Plugin::Range; use Monitoring::Plugin::Functions qw(:codes plugin_die); our ($VERSION) = $Monitoring::Plugin::Functions::VERSION; sub get_status { my ($self, $value) = @_; $value = [ $value ] if (ref $value eq ""); foreach my $v (@$value) { if ($self->critical->is_set) { return CRITICAL if $self->critical->check_range($v); } } foreach my $v (@$value) { if ($self->warning->is_set) { return WARNING if $self->warning->check_range($v); } } return OK; } sub _inflate { my ($self, $value, $key) = @_; # Return an undefined range if $value is undef return Monitoring::Plugin::Range->new if ! defined $value; # For refs, check isa N::P::Range if (ref $value) { plugin_die("Invalid $key object: type " . ref $value) unless $value->isa("Monitoring::Plugin::Range"); return $value; } # Another quick exit if $value is an empty string return Monitoring::Plugin::Range->new if $value eq ""; # Otherwise parse $value my $range = Monitoring::Plugin::Range->parse_range_string($value); plugin_die("Cannot parse $key range: '$value'") unless(defined($range)); return $range; } sub set_thresholds { my ($self, %arg) = @_; # Equals new() as a class method return $self->new(%arg) unless ref $self; # On an object, just acts as special mutator $self->set($_, $arg{$_}) foreach qw(warning critical); } sub set { my $self = shift; my ($key, $value) = @_; $self->SUPER::set($key, $self->_inflate($value, $key)); } # Constructor - inflate scalars to N::P::Range objects sub new { my ($self, %arg) = @_; $self->SUPER::new({ map { $_ => $self->_inflate($arg{$_}, $_) } qw(warning critical) }); } 1; __END__ =head1 NAME Monitoring::Plugin::Threshold - class for handling Monitoring::Plugin thresholds. =head1 SYNOPSIS # NB: This is an internal Monitoring::Plugin class. # See Monitoring::Plugin itself for public interfaces. # Constructor $t = Monitoring::Plugin::Threshold->set_thresholds( warning => $warning_range_string, critical => $critical_range_string, ); # Value checking - returns CRITICAL if in the critical range, # WARNING if in the warning range, and OK otherwise $status = $t->get_status($value); # Accessors - return the associated N::P::Range object $warning_range = $t->warning; $critical_range = $t->critical; =head1 DESCRIPTION Internal Monitoring::Plugin class for handling threshold data. See Monitoring::Plugin for public interfaces. A threshold object contains (typically) a pair of ranges, associated with a particular severity e.g. warning => range1 critical => range2 =head1 AUTHOR This code is maintained by the Monitoring Plugin Development Team: see https://monitoring-plugins.org =head1 COPYRIGHT AND LICENSE Copyright (C) 2014 by Monitoring Plugin Team Copyright (C) 2006-2014 by Nagios Plugin Development Team This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Monitoring-Plugin-0.40/lib/Monitoring/Plugin/Config.pm0000644000175000017500000001302312267223737021434 0ustar svensvenpackage Monitoring::Plugin::Config; use 5.006; use strict; use warnings; use Carp; use File::Spec; use base qw(Config::Tiny); my $FILENAME1 = 'plugins.ini'; my $FILENAME2 = 'nagios-plugins.ini'; my $FILENAME3 = 'monitoring-plugins.ini'; my $CURRENT_FILE = undef; # Config paths ending in nagios (search for $FILENAME1) my @MONITORING_CONFIG_PATH = qw(/etc/nagios /usr/local/nagios/etc /usr/local/etc/nagios /etc/opt/nagios); # Config paths not ending in nagios (search for $FILENAME2) my @CONFIG_PATH = qw(/etc /usr/local/etc /etc/opt); # Override Config::Tiny::read to default the filename, if not given sub read { my $class = shift; unless ($_[0]) { SEARCH: { if ($ENV{MONITORING_CONFIG_PATH} || $ENV{NAGIOS_CONFIG_PATH}) { for (split /:/, ($ENV{MONITORING_CONFIG_PATH} || $ENV{NAGIOS_CONFIG_PATH})) { my $file = File::Spec->catfile($_, $FILENAME1); unshift(@_, $file), last SEARCH if -f $file; $file = File::Spec->catfile($_, $FILENAME2); unshift(@_, $file), last SEARCH if -f $file; $file = File::Spec->catfile($_, $FILENAME3); unshift(@_, $file), last SEARCH if -f $file; } } for (@MONITORING_CONFIG_PATH) { my $file = File::Spec->catfile($_, $FILENAME1); unshift(@_, $file), last SEARCH if -f $file; } for (@CONFIG_PATH) { my $file = File::Spec->catfile($_, $FILENAME2); unshift(@_, $file), last SEARCH if -f $file; $file = File::Spec->catfile($_, $FILENAME3); unshift(@_, $file), last SEARCH if -f $file; } } # Use die instead of croak, so we can pass a clean message downstream die "Cannot find '$FILENAME1', '$FILENAME2' or '$FILENAME3' in any standard location.\n" unless $_[0]; } $CURRENT_FILE = $_[0]; $class->SUPER::read( @_ ); } # Straight from Config::Tiny - only changes are repeated property key support # Would be nice if we could just override the per-line handling ... sub read_string { my $class = ref $_[0] ? ref shift : shift; my $self = bless {}, $class; return undef unless defined $_[0]; # Parse the file my $ns = '_'; my $counter = 0; foreach ( split /(?:\015{1,2}\012|\015|\012)/, shift ) { $counter++; # Skip comments and empty lines next if /^\s*(?:\#|\;|$)/; # Handle section headers if ( /^\s*\[\s*(.+?)\s*\]\s*$/ ) { # Create the sub-hash if it doesn't exist. # Without this sections without keys will not # appear at all in the completed struct. $self->{$ns = $1} ||= {}; next; } # Handle properties if ( /^\s*([^=]+?)\s*=\s*(.*?)\s*$/ ) { push @{$self->{$ns}->{$1}}, $2; next; } return $self->_error( "Syntax error at line $counter: '$_'" ); } $self; } sub write { croak "Write access not permitted" } # Return last file used by read(); sub mp_getfile { return $CURRENT_FILE; } 1; __END__ =head1 NAME Monitoring::Plugin::Config - read nagios plugin .ini style config files =head1 SYNOPSIS # Read given nagios plugin config file $Config = Monitoring::Plugin::Config->read( '/etc/nagios/plugins.ini' ); # Search for and read default nagios plugin config file $Config = Monitoring::Plugin::Config->read(); # Access sections and properties (returns scalars or arrayrefs) $rootproperty = $Config->{_}->{rootproperty}; $one = $Config->{section}->{one}; $Foo = $Config->{section}->{Foo}; =head1 DESCRIPTION Monitoring::Plugin::Config is a subclass of the excellent Config::Tiny, with the following changes: =over 4 =item Repeated keys are allowed within sections, returning lists instead of scalars =item Write functionality has been removed i.e. access is read only =item Monitoring::Plugin::Config searches for a default nagios plugins file if no explicit filename is given to C. The current standard locations checked are: =over 4 =item /etc/nagios/plugins.ini =item /usr/local/nagios/etc/plugins.ini =item /usr/local/etc/nagios /etc/opt/nagios/plugins.ini =item /etc/nagios-plugins.ini =item /usr/local/etc/nagios-plugins.ini =item /etc/opt/nagios-plugins.ini =back To use a custom location, set a C environment variable to the set of directories that should be checked. The first C or C file found will be used. =back =head1 SEE ALSO L, L =head1 AUTHOR This code is maintained by the Monitoring Plugin Development Team: see https://monitoring-plugins.org =head1 COPYRIGHT AND LICENSE Copyright (C) 2014 by Monitoring Plugin Team Copyright (C) 2006-2014 by Nagios Plugin Development Team This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Monitoring-Plugin-0.40/lib/Monitoring/Plugin/Getopt.pm0000644000175000017500000005541313326153550021472 0ustar svensvenpackage Monitoring::Plugin::Getopt; # # Monitoring::Plugin::Getopt - OO perl module providing standardised argument # processing for nagios plugins # use 5.006; use strict; use warnings; use File::Basename; use Getopt::Long qw(:config no_ignore_case bundling); use Carp; use Params::Validate qw(:all); use base qw(Class::Accessor); use Monitoring::Plugin::Functions; use Monitoring::Plugin::Config; use vars qw($VERSION); $VERSION = $Monitoring::Plugin::Functions::VERSION; # Standard defaults my %DEFAULT = ( timeout => 15, verbose => 0, license => "This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY. It may be used, redistributed and/or modified under the terms of the GNU General Public Licence (see http://www.fsf.org/licensing/licenses/gpl.txt).", ); # Standard arguments my @ARGS = ({ spec => 'usage|?', help => "-?, --usage\n Print usage information", }, { spec => 'help|h', help => "-h, --help\n Print detailed help screen", }, { spec => 'version|V', help => "-V, --version\n Print version information", }, { spec => 'extra-opts:s@', help => "--extra-opts=[section][\@file]\n Read options from an ini file. See https://www.monitoring-plugins.org/doc/extra-opts.html\n for usage and examples.", }, { spec => 'timeout|t=i', help => "-t, --timeout=INTEGER\n Seconds before plugin times out (default: %s)", default => $DEFAULT{timeout}, }, { spec => 'verbose|v+', help => "-v, --verbose\n Show details for command-line debugging (can repeat up to 3 times)", default => $DEFAULT{verbose}, }, ); # Standard arguments we traditionally display last in the help output my %DEFER_ARGS = map { $_ => 1 } qw(timeout verbose); # ------------------------------------------------------------------------- # Private methods sub _die { my $self = shift; my ($msg) = @_; $msg .= "\n" unless substr($msg, -1) eq "\n"; Monitoring::Plugin::Functions::_plugin_exit(3, $msg); } # Return the given attribute, if set, including a final newline sub _attr { my $self = shift; my ($item, $extra) = @_; $extra = '' unless defined $extra; return '' unless $self->{_attr}->{$item}; $self->{_attr}->{$item} . "\n" . $extra; } # Turn argument spec into help-style output sub _spec_to_help { my ($self, $spec, $label) = @_; my ($opts, $type) = split /=|:|!/, $spec, 2; my $optional = ($spec =~ m/:/); my $boolean = ($spec =~ m/!/); my (@short, @long); for (split /\|/, $opts) { if (length $_ == 1) { push @short, "-$_"; } else { push @long, $boolean ? "--[no-]$_" : "--$_"; } } my $help = join(', ', @short, @long); if ($type) { if (!$label) { if ($type eq 'i' || $type eq '+' || $type =~ /\d+/) { $label = 'INTEGER'; } else { $label = 'STRING'; } } if ($optional) { $help .= '[=' . $label . ']'; } else { $help .= '=' . $label; } } elsif ($label) { carp "Label specified, but there's no type in spec '$spec'"; } $help .= "\n "; return $help; } # Options output for plugin -h sub _options { my $self = shift; my @args = (); my @defer = (); for (@{$self->{_args}}) { if (exists $DEFER_ARGS{$_->{name}}) { push @defer, $_; } else { push @args, $_; } } my @options = (); for my $arg (@args, @defer) { my $help_array = ref $arg->{help} && ref $arg->{help} eq 'ARRAY' ? $arg->{help} : [ $arg->{help} ]; my $label_array = $arg->{label} && ref $arg->{label} && ref $arg->{label} eq 'ARRAY' ? $arg->{label} : [ $arg->{label} ]; my $help_string = ''; for (my $i = 0; $i <= $#$help_array; $i++) { my $help = $help_array->[$i]; # Add spec arguments to help if not already there if ($help =~ m/^\s*-/) { $help_string .= $help; } else { $help_string .= $self->_spec_to_help($arg->{spec}, $label_array->[$i]) . $help; $help_string .= "\n " if $i < $#$help_array; } } # Add help_string to @options if ($help_string =~ m/%s/) { my $default = defined $arg->{default} ? $arg->{default} : ''; # We only handle '%s' formats here my $replaced = $help_string; $replaced =~ s|%s|$default|gmx; push @options, $replaced; } else { push @options, $help_string; } } return ' ' . join("\n ", @options); } # Output for plugin -? (or missing/invalid args) sub _usage { my $self = shift; my $usage = $self->_attr('usage'); $usage =~ s|%s|$self->{_attr}->{plugin}|gmx; return($usage); } # Output for plugin -V sub _revision { my $self = shift; my $revision = sprintf "%s %s", $self->{_attr}->{plugin}, $self->{_attr}->{version}; $revision .= sprintf " [%s]", $self->{_attr}->{url} if $self->{_attr}->{url}; $revision .= "\n"; $revision; } # Output for plugin -h sub _help { my $self = shift; my $help = ''; $help .= $self->_revision . "\n"; $help .= $self->_attr('license', "\n"); $help .= $self->_attr('blurb', "\n"); $help .= $self->_usage ? $self->_usage . "\n" : ''; $help .= $self->_options ? $self->_options . "\n" : ''; $help .= $self->_attr('extra', "\n"); return $help; } # Return a Getopt::Long-compatible option array from the current set of specs sub _process_specs_getopt_long { my $self = shift; my @opts = (); for my $arg (@{$self->{_args}}) { push @opts, $arg->{spec}; # Setup names and defaults my $spec = $arg->{spec}; # Use first arg as name (like Getopt::Long does) $spec =~ s/[=:!].*$//; my $name = (split /\s*\|\s*/, $spec)[0]; $arg->{name} = $name; if (defined $self->{$name}) { $arg->{default} = $self->{$name}; } else { $self->{$name} = $arg->{default}; } } return @opts; } # Check for existence of required arguments sub _check_required_opts { my $self = shift; my @missing = (); for my $arg (@{$self->{_args}}) { if ($arg->{required} && ! defined $self->{$arg->{name}}) { push @missing, $arg->{name}; } } if (@missing) { $self->_die($self->_usage . "\n" . join("\n", map { sprintf "Missing argument: %s", $_ } @missing) . "\n"); } } # Process and handle any immediate options sub _process_opts { my $self = shift; # Print message and exit for usage, version, help $self->_die($self->_usage) if $self->{usage}; $self->_die($self->_revision) if $self->{version}; $self->_die($self->_help) if $self->{help}; } # ------------------------------------------------------------------------- # Default opts methods sub _load_config_section { my $self = shift; my ($section, $file, $flags) = @_; $section ||= $self->{_attr}->{plugin}; my $Config; eval { $Config = Monitoring::Plugin::Config->read($file); }; $self->_die($@) if ($@); defined $Config or $self->_die(Monitoring::Plugin::Config->errstr); # TODO: is this check sane? Does --extra-opts=foo require a [foo] section? ## Nevertheless, if we die as UNKNOWN here we should do the same on default ## file *added eval/_die above*. $file ||= $Config->mp_getfile(); $self->_die("Invalid section '$section' in config file '$file'") unless exists $Config->{$section}; return $Config->{$section}; } # Helper method to setup a hash of spec definitions for _cmdline sub _setup_spec_index { my $self = shift; return if defined $self->{_spec}; $self->{_spec} = { map { $_->{name} => $_->{spec} } @{$self->{_args}} }; } # Quote values that require it sub _cmdline_value { my $self = shift; local $_ = shift; if (m/\s/ && (m/^[^"']/ || m/[^"']$/)) { return qq("$_"); } elsif ($_ eq '') { return q(""); } else { return $_; } } # Helper method to format key/values in $hash in a quasi-commandline format sub _cmdline { my $self = shift; my ($hash) = @_; $hash ||= $self; $self->_setup_spec_index; my @args = (); for my $key (sort keys %$hash) { # Skip internal keys next if $key =~ m/^_/; # Skip defaults and internals next if exists $DEFAULT{$key} && $hash->{$key} eq $DEFAULT{$key}; next if grep { $key eq $_ } qw(help usage version extra-opts); next unless defined $hash->{$key}; # Render arg my $spec = $self->{_spec}->{$key} || ''; if ($spec =~ m/[=:].+$/) { # Arg takes value - may be a scalar or an arrayref for my $value (ref $hash->{$key} eq 'ARRAY' ? @{$hash->{$key}} : ( $hash->{$key} )) { $value = $self->_cmdline_value($value); if (length($key) > 1) { push @args, sprintf "--%s=%s", $key, $value; } else { push @args, "-$key", $value; } } } else { # Flag - render long or short based on option length push @args, (length($key) > 1 ? '--' : '-') . $key; } } return wantarray ? @args : join(' ', @args); } # Process and load extra-opts sections sub _process_extra_opts { my $self = shift; my ($args) = @_; my $extopts_list = $args->{'extra-opts'}; my @sargs = (); for my $extopts (@$extopts_list) { $extopts ||= $self->{_attr}->{plugin}; my $section = $extopts; my $file = ''; # Parse section@file if ($extopts =~ m/^([^@]*)@(.*?)\s*$/) { $section = $1; $file = $2; } # Load section args my $shash = $self->_load_config_section($section, $file); # Turn $shash into a series of commandline-like arguments push @sargs, $self->_cmdline($shash); } # Reset ARGV to extra-opts + original @ARGV = ( @sargs, @{$self->{_attr}->{argv}} ); printf "[extra-opts] %s %s\n", $self->{_attr}->{plugin}, join(' ', @ARGV) if $args->{verbose} && $args->{verbose} >= 3; } # ------------------------------------------------------------------------- # Public methods # Define plugin argument sub arg { my $self = shift; my %args; # Param name to required boolean my %params = ( spec => 1, help => 1, default => 0, required => 0, label => 0, ); # Named args if (exists $params{$_[0]} && @_ % 2 == 0) { %args = validate( @_, \%params ); } # Positional args else { my @order = qw(spec help default required label); @args{@order} = validate_pos(@_, @params{@order}); } # Add to private args arrayref push @{$self->{_args}}, \%args; } # Process the @ARGV array using the current _args list (possibly exiting) sub getopts { my $self = shift; # Collate spec arguments for Getopt::Long my @opt_array = $self->_process_specs_getopt_long; # Capture original @ARGV (for extra-opts games) $self->{_attr}->{argv} = [ @ARGV ]; # Call GetOptions using @opt_array my $args1 = {}; my $ok = GetOptions($args1, @opt_array); # Invalid options - give usage message and exit $self->_die($self->_usage) unless $ok; # Process extra-opts $self->_process_extra_opts($args1); # Call GetOptions again, this time including extra-opts $ok = GetOptions($self, @opt_array); # Invalid options - give usage message and exit $self->_die($self->_usage) unless $ok; # Process immediate options (possibly exiting) $self->_process_opts; # Required options (possibly exiting) $self->_check_required_opts; # Setup accessors for options $self->mk_ro_accessors(grep ! /^_/, keys %$self); # Setup default alarm handler for alarm($ng->timeout) in plugin $SIG{ALRM} = sub { my $plugin = uc $self->{_attr}->{plugin}; $plugin =~ s/^CHECK[-_]//i; $self->_die( sprintf("%s UNKNOWN - plugin timed out (timeout %ss)", $plugin, $self->timeout)); }; } # ------------------------------------------------------------------------- # Constructor sub _init { my $self = shift; # Check params my $plugin = basename($ENV{PLUGIN_NAME} || $ENV{NAGIOS_PLUGIN} || $0); my %attr = validate( @_, { usage => 1, version => 0, url => 0, plugin => { default => $plugin }, blurb => 0, extra => 0, 'extra-opts' => 0, license => { default => $DEFAULT{license} }, timeout => { default => $DEFAULT{timeout} }, }); # Add attr to private _attr hash (except timeout) $self->{timeout} = delete $attr{timeout}; $self->{_attr} = { %attr }; # Chomp _attr values chomp foreach values %{$self->{_attr}}; # Setup initial args list $self->{_args} = [ @ARGS ]; $self } sub new { my $class = shift; my $self = bless {}, $class; $self->_init(@_); } # ------------------------------------------------------------------------- 1; __END__ =head1 NAME Monitoring::Plugin::Getopt - OO perl module providing standardised argument processing for Nagios plugins =head1 SYNOPSIS use Monitoring::Plugin::Getopt; # Instantiate object (usage is mandatory) $ng = Monitoring::Plugin::Getopt->new( usage => "Usage: %s -H -w -c ", version => '0.1', url => 'http://www.openfusion.com.au/labs/nagios/', blurb => 'This plugin tests various stuff.', ); # Add argument - named parameters (spec and help are mandatory) $ng->arg( spec => 'critical|c=i', help => q(Exit with CRITICAL status if fewer than INTEGER foobars are free), required => 1, default => 10, ); # Add argument - positional parameters - arg spec, help text, # default value, required? (first two mandatory) $ng->arg( 'warning|w=i', q(Exit with WARNING status if fewer than INTEGER foobars are free), 5, 1); # Parse arguments and process standard ones (e.g. usage, help, version) $ng->getopts; # Access arguments using named accessors or or via the generic get() print $ng->opts->warning; print $ng->opts->get('critical'); =head1 DESCRIPTION Monitoring::Plugin::Getopt is an OO perl module providing standardised and simplified argument processing for Nagios plugins. It implements a number of standard arguments itself (--help, --version, --usage, --timeout, --verbose, and their short form counterparts), produces standardised nagios plugin help output, and allows additional arguments to be easily defined. =head2 CONSTRUCTOR # Instantiate object (usage is mandatory) $ng = Monitoring::Plugin::Getopt->new( usage => 'Usage: %s --hello', version => '0.01', ); The Monitoring::Plugin::Getopt constructor accepts the following named arguments: =over 4 =item usage (required) Short usage message used with --usage/-? and with missing required arguments, and included in the longer --help output. Can include a '%s' sprintf placeholder which will be replaced with the plugin name e.g. usage => qq(Usage: %s -H -p [-v]), might be displayed as: $ ./check_tcp_range --usage Usage: check_tcp_range -H -p [-v] =item version (required) Plugin version number, included in the --version/-V output, and in the longer --help output. e.g. $ ./check_tcp_range --version check_tcp_range 0.2 [http://www.openfusion.com.au/labs/nagios/] =item url URL for info about this plugin, included in the --version/-V output, and in the longer --help output (see preceding 'version' example). =item blurb Short plugin description, included in the longer --help output (see below for an example). =item license License text, included in the longer --help output (see below for an example). By default, this is set to the standard nagios plugins GPL license text: This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY. It may be used, redistributed and/or modified under the terms of the GNU General Public Licence (see http://www.fsf.org/licensing/licenses/gpl.txt). Provide your own to replace this text in the help output. =item extra Extra text to be appended at the end of the longer --help output. =item plugin Plugin name. This defaults to the basename of your plugin, which is usually correct, but you can set it explicitly if not. =item timeout Timeout period in seconds, overriding the standard timeout default (15 seconds). =back The full --help output has the following form: version string license string blurb usage string options list extra text The 'blurb' and 'extra text' sections are omitted if not supplied. For example: $ ./check_tcp_range -h check_tcp_range 0.2 [http://www.openfusion.com.au/labs/nagios/] This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY. It may be used, redistributed and/or modified under the terms of the GNU General Public Licence (see http://www.fsf.org/licensing/licenses/gpl.txt). This plugin tests arbitrary ranges/sets of tcp ports for a host. Usage: check_tcp_range -H -p [-v] Options: -h, --help Print detailed help screen -V, --version Print version information -H, --hostname=ADDRESS Host name or IP address -p, --ports=STRING Port numbers to check. Format: comma-separated, colons for ranges, no spaces e.g. 8700:8705,8710:8715,8760 -t, --timeout=INTEGER Seconds before plugin times out (default: 15) -v, --verbose Show details for command-line debugging (can repeat up to 3 times) =head2 ARGUMENTS You can define arguments for your plugin using the arg() method, which supports both named and positional arguments. In both cases the C and C arguments are required, while the C