diff options
| -rw-r--r-- | .cvsignore | 2 | ||||
| -rw-r--r-- | MANIFEST | 1 | ||||
| -rw-r--r-- | lib/Nagios/Plugin/Getopt.pm | 603 | ||||
| -rw-r--r-- | t/Nagios-Plugin-Getopt-01.t | 134 | ||||
| -rw-r--r-- | t/Nagios-Plugin-Getopt-02.t | 61 |
5 files changed, 801 insertions, 0 deletions
| @@ -1,3 +1,5 @@ | |||
| 1 | Makefile | 1 | Makefile |
| 2 | blib | 2 | blib |
| 3 | pm_to_blib | 3 | pm_to_blib |
| 4 | .bzr | ||
| 5 | .bzrignore | ||
| @@ -11,4 +11,5 @@ lib/Nagios/Plugin/Performance.pm | |||
| 11 | lib/Nagios/Plugin/Range.pm | 11 | lib/Nagios/Plugin/Range.pm |
| 12 | lib/Nagios/Plugin/Threshold.pm | 12 | lib/Nagios/Plugin/Threshold.pm |
| 13 | lib/Nagios/Plugin/Base.pm | 13 | lib/Nagios/Plugin/Base.pm |
| 14 | lib/Nagios/Plugin/Getopt.pm | ||
| 14 | META.yml Module meta-data (added by MakeMaker) | 15 | META.yml Module meta-data (added by MakeMaker) |
diff --git a/lib/Nagios/Plugin/Getopt.pm b/lib/Nagios/Plugin/Getopt.pm new file mode 100644 index 0000000..dedf92c --- /dev/null +++ b/lib/Nagios/Plugin/Getopt.pm | |||
| @@ -0,0 +1,603 @@ | |||
| 1 | # | ||
| 2 | # Nagios::Plugin::Getopt - OO perl module providing standardised argument | ||
| 3 | # processing for nagios plugins | ||
| 4 | # | ||
| 5 | |||
| 6 | package Nagios::Plugin::Getopt; | ||
| 7 | |||
| 8 | use 5.005003; | ||
| 9 | use strict; | ||
| 10 | use File::Basename; | ||
| 11 | use Getopt::Long qw(:config no_ignore_case bundling); | ||
| 12 | use Carp; | ||
| 13 | use Params::Validate qw(:all); | ||
| 14 | use base qw(Class::Accessor); | ||
| 15 | |||
| 16 | use vars qw($VERSION); | ||
| 17 | $VERSION = '0.02'; | ||
| 18 | |||
| 19 | # Standard defaults | ||
| 20 | my %DEFAULT = ( | ||
| 21 | timeout => 15, | ||
| 22 | verbose => 0, | ||
| 23 | licence => | ||
| 24 | "This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY. | ||
| 25 | It may be used, redistributed and/or modified under the terms of the GNU | ||
| 26 | General Public Licence (see http://www.fsf.org/licensing/licenses/gpl.txt).", | ||
| 27 | ); | ||
| 28 | # Standard arguments | ||
| 29 | my @ARGS = ({ | ||
| 30 | spec => 'usage|?', | ||
| 31 | help => "-?, --usage\n Print usage information", | ||
| 32 | }, { | ||
| 33 | spec => 'help|h', | ||
| 34 | help => "-h, --help\n Print detailed help screen", | ||
| 35 | }, { | ||
| 36 | spec => 'version|V', | ||
| 37 | help => "-V, --version\n Print version information", | ||
| 38 | }, { | ||
| 39 | spec => 'timeout|t=i', | ||
| 40 | help => "-t, --timeout=INTEGER\n Seconds before plugin times out (default: %s)", | ||
| 41 | default => $DEFAULT{timeout}, | ||
| 42 | }, { | ||
| 43 | spec => 'verbose|v', | ||
| 44 | help => "-v, --verbose\n Show details for command-line debugging", | ||
| 45 | default => $DEFAULT{verbose}, | ||
| 46 | }, | ||
| 47 | ); | ||
| 48 | # Standard arguments we traditionally display last in the help output | ||
| 49 | my %DEFER_ARGS = map { $_ => 1 } qw(timeout verbose); | ||
| 50 | |||
| 51 | # ------------------------------------------------------------------------- | ||
| 52 | # Private methods | ||
| 53 | |||
| 54 | sub _die | ||
| 55 | { | ||
| 56 | my $self = shift; | ||
| 57 | my ($msg) = @_; | ||
| 58 | $msg .= "\n" unless substr($msg, -1) eq "\n"; | ||
| 59 | # Set errno to UNKNOWN for die return code | ||
| 60 | local $! = 3; | ||
| 61 | die $msg; | ||
| 62 | } | ||
| 63 | |||
| 64 | # Return the given attribute, if set, including a final newline | ||
| 65 | sub _attr | ||
| 66 | { | ||
| 67 | my $self = shift; | ||
| 68 | my ($item, $extra) = @_; | ||
| 69 | $extra = '' unless defined $extra; | ||
| 70 | return '' unless $self->{_attr}->{$item}; | ||
| 71 | $self->{_attr}->{$item} . "\n" . $extra; | ||
| 72 | } | ||
| 73 | |||
| 74 | # Options output for plugin -h | ||
| 75 | sub _options | ||
| 76 | { | ||
| 77 | my $self = shift; | ||
| 78 | |||
| 79 | my @args = (); | ||
| 80 | my @defer = (); | ||
| 81 | for (@{$self->{_args}}) { | ||
| 82 | if (exists $DEFER_ARGS{$_->{name}}) { | ||
| 83 | push @defer, $_; | ||
| 84 | } else { | ||
| 85 | push @args, $_; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | my @options = (); | ||
| 90 | for my $arg (@args, @defer) { | ||
| 91 | if ($arg->{help} =~ m/%s/) { | ||
| 92 | push @options, sprintf($arg->{help}, $arg->{default} || ''); | ||
| 93 | } else { | ||
| 94 | push @options, $arg->{help}; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | return ' ' . join("\n ", @options); | ||
| 99 | } | ||
| 100 | |||
| 101 | # Output for plugin -? (or missing/invalid args) | ||
| 102 | sub _usage | ||
| 103 | { | ||
| 104 | my $self = shift; | ||
| 105 | sprintf $self->_attr('usage'), $self->{_attr}->{plugin}; | ||
| 106 | } | ||
| 107 | |||
| 108 | # Output for plugin -V | ||
| 109 | sub _revision | ||
| 110 | { | ||
| 111 | my $self = shift; | ||
| 112 | my $revision = sprintf "%s %s", $self->{_attr}->{plugin}, $self->{_attr}->{version}; | ||
| 113 | $revision .= sprintf " [%s]", $self->{_attr}->{url} if $self->{_attr}->{url}; | ||
| 114 | $revision .= "\n"; | ||
| 115 | $revision; | ||
| 116 | } | ||
| 117 | |||
| 118 | # Output for plugin -h | ||
| 119 | sub _help | ||
| 120 | { | ||
| 121 | my $self = shift; | ||
| 122 | my $help = ''; | ||
| 123 | $help .= $self->_revision . "\n"; | ||
| 124 | $help .= $self->_attr('license', "\n"); | ||
| 125 | $help .= $self->_attr('blurb', "\n"); | ||
| 126 | $help .= $self->_usage ? $self->_usage . "\n" : ''; | ||
| 127 | $help .= $self->_options ? $self->_options . "\n" : ''; | ||
| 128 | $help .= $self->_attr('extra', "\n"); | ||
| 129 | return $help; | ||
| 130 | } | ||
| 131 | |||
| 132 | # Return a Getopt::Long-compatible option array from the current set of specs | ||
| 133 | sub _process_specs_getopt_long | ||
| 134 | { | ||
| 135 | my $self = shift; | ||
| 136 | |||
| 137 | my @opts = (); | ||
| 138 | for my $arg (@{$self->{_args}}) { | ||
| 139 | push @opts, $arg->{spec}; | ||
| 140 | # Setup names and defaults | ||
| 141 | my $spec = $arg->{spec}; | ||
| 142 | # Use first arg as name (like Getopt::Long does) | ||
| 143 | $spec =~ s/=\w+$//; | ||
| 144 | my $name = (split /\s*\|\s*/, $spec)[0]; | ||
| 145 | $arg->{name} = $name; | ||
| 146 | if (defined $self->{$name}) { | ||
| 147 | $arg->{default} = $self->{$name}; | ||
| 148 | } else { | ||
| 149 | $self->{$name} = $arg->{default}; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | return @opts; | ||
| 154 | } | ||
| 155 | |||
| 156 | # Check for existence of required arguments | ||
| 157 | sub _check_required_opts | ||
| 158 | { | ||
| 159 | my $self = shift; | ||
| 160 | |||
| 161 | my @missing = (); | ||
| 162 | for my $arg (@{$self->{_args}}) { | ||
| 163 | if ($arg->{required} && ! defined $self->{$arg->{name}}) { | ||
| 164 | push @missing, $arg->{name}; | ||
| 165 | } | ||
| 166 | } | ||
| 167 | if (@missing) { | ||
| 168 | $self->_die($self->_usage . "\n" . | ||
| 169 | join("\n", map { sprintf "Missing argument: %s", $_ } @missing) . "\n"); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | # Process and handle any immediate options | ||
| 174 | sub _process_opts | ||
| 175 | { | ||
| 176 | my $self = shift; | ||
| 177 | |||
| 178 | # Print message and exit for usage, version, help | ||
| 179 | $self->_die($self->_usage) if $self->{usage}; | ||
| 180 | $self->_die($self->_revision) if $self->{version}; | ||
| 181 | $self->_die($self->_help) if $self->{help}; | ||
| 182 | } | ||
| 183 | |||
| 184 | # ------------------------------------------------------------------------- | ||
| 185 | # Public methods | ||
| 186 | |||
| 187 | # Define plugin argument | ||
| 188 | sub arg | ||
| 189 | { | ||
| 190 | my $self = shift; | ||
| 191 | my %args; | ||
| 192 | |||
| 193 | # Named args | ||
| 194 | if ($_[0] =~ m/^(spec|help|required|default)$/ && scalar(@_) % 2 == 0) { | ||
| 195 | %args = validate( @_, { | ||
| 196 | spec => 1, | ||
| 197 | help => 1, | ||
| 198 | default => 0, | ||
| 199 | required => 0, | ||
| 200 | }); | ||
| 201 | } | ||
| 202 | |||
| 203 | # Positional args | ||
| 204 | else { | ||
| 205 | my @args = validate_pos(@_, 1, 1, 0, 0); | ||
| 206 | %args = ( | ||
| 207 | spec => $args[0], | ||
| 208 | help => $args[1], | ||
| 209 | default => $args[2], | ||
| 210 | required => $args[3], | ||
| 211 | ); | ||
| 212 | } | ||
| 213 | |||
| 214 | # Add to private args arrayref | ||
| 215 | push @{$self->{_args}}, \%args; | ||
| 216 | } | ||
| 217 | |||
| 218 | # Process the @ARGV array using the current _args list (possibly exiting) | ||
| 219 | sub getopts | ||
| 220 | { | ||
| 221 | my $self = shift; | ||
| 222 | |||
| 223 | # Collate spec arguments for Getopt::Long | ||
| 224 | my @opt_array = $self->_process_specs_getopt_long; | ||
| 225 | |||
| 226 | # Call GetOptions using @opt_array | ||
| 227 | my $ok = GetOptions($self, @opt_array); | ||
| 228 | |||
| 229 | # Invalid options - given usage message and exit | ||
| 230 | $self->_die($self->_usage) unless $ok; | ||
| 231 | |||
| 232 | # Process immediate options (possibly exiting) | ||
| 233 | $self->_process_opts; | ||
| 234 | |||
| 235 | # Required options (possibly exiting) | ||
| 236 | $self->_check_required_opts; | ||
| 237 | |||
| 238 | # Setup accessors for options | ||
| 239 | $self->mk_ro_accessors(grep ! /^_/, keys %$self); | ||
| 240 | |||
| 241 | # Setup default alarm handler for alarm($ng->timeout) in plugin | ||
| 242 | $SIG{ALRM} = sub { | ||
| 243 | my $plugin = uc $self->{_attr}->{plugin}; | ||
| 244 | $plugin =~ s/^check_//; | ||
| 245 | $self->_die( | ||
| 246 | sprintf("%s UNKNOWN - plugin timed out (timeout %ss)", | ||
| 247 | $plugin, $self->timeout)); | ||
| 248 | }; | ||
| 249 | } | ||
| 250 | |||
| 251 | # ------------------------------------------------------------------------- | ||
| 252 | # Constructor | ||
| 253 | |||
| 254 | sub _init | ||
| 255 | { | ||
| 256 | my $self = shift; | ||
| 257 | |||
| 258 | # Check params | ||
| 259 | my $plugin = basename($ENV{NAGIOS_PLUGIN} || $0); | ||
| 260 | my %attr = validate( @_, { | ||
| 261 | usage => 1, | ||
| 262 | version => 0, | ||
| 263 | url => 0, | ||
| 264 | plugin => { default => $plugin }, | ||
| 265 | blurb => 0, | ||
| 266 | extra => 0, | ||
| 267 | license => { default => $DEFAULT{licence} }, | ||
| 268 | timeout => { default => $DEFAULT{timeout} }, | ||
| 269 | }); | ||
| 270 | |||
| 271 | # Add attr to private _attr hash (except timeout) | ||
| 272 | $self->{timeout} = delete $attr{timeout}; | ||
| 273 | $self->{_attr} = { %attr }; | ||
| 274 | # Chomp _attr values | ||
| 275 | chomp foreach values %{$self->{_attr}}; | ||
| 276 | |||
| 277 | # Setup initial args list | ||
| 278 | $self->{_args} = [ @ARGS ]; | ||
| 279 | |||
| 280 | $self | ||
| 281 | } | ||
| 282 | |||
| 283 | sub new | ||
| 284 | { | ||
| 285 | my $class = shift; | ||
| 286 | my $self = bless {}, $class; | ||
| 287 | $self->_init(@_); | ||
| 288 | } | ||
| 289 | |||
| 290 | # ------------------------------------------------------------------------- | ||
| 291 | |||
| 292 | 1; | ||
| 293 | |||
| 294 | __END__ | ||
| 295 | |||
| 296 | =head1 NAME | ||
| 297 | |||
| 298 | Nagios::Plugin::Getopt - OO perl module providing standardised argument | ||
| 299 | processing for Nagios plugins | ||
| 300 | |||
| 301 | |||
| 302 | =head1 VERSION | ||
| 303 | |||
| 304 | This documentation applies to version 0.01 of Nagios::Plugin::Getopt. | ||
| 305 | |||
| 306 | |||
| 307 | =head1 SYNOPSIS | ||
| 308 | |||
| 309 | use Nagios::Plugin::Getopt; | ||
| 310 | |||
| 311 | # Instantiate object (usage and version are mandatory) | ||
| 312 | $ng = Nagios::Plugin::Getopt->new( | ||
| 313 | usage => "Usage: %s -H <host> -w <warning_threshold> | ||
| 314 | -c <critical threshold>", | ||
| 315 | version => '0.01', | ||
| 316 | url => 'http://www.openfusion.com.au/labs/nagios/', | ||
| 317 | blurb => 'This plugin tests various stuff.', | ||
| 318 | ); | ||
| 319 | |||
| 320 | # Add argument - named parameters (spec and help are mandatory) | ||
| 321 | $ng->arg( | ||
| 322 | spec => 'critical|c=s', | ||
| 323 | help => qq(-c, --critical=INTEGER\n Exit with CRITICAL status if fewer than INTEGER foobars are free), | ||
| 324 | required => 1, | ||
| 325 | default => 10, | ||
| 326 | ); | ||
| 327 | |||
| 328 | # Add argument - positional parameters - arg spec, help text, | ||
| 329 | # default value, required? (first two mandatory) | ||
| 330 | $ng->arg( | ||
| 331 | 'warning|w=s', | ||
| 332 | qq(-w, --warning=INTEGER\n Exit with WARNING status if fewer than INTEGER foobars are free), | ||
| 333 | 5, | ||
| 334 | 1); | ||
| 335 | |||
| 336 | # Parse arguments and process standard ones (e.g. usage, help, version) | ||
| 337 | $ng->getopts; | ||
| 338 | |||
| 339 | # Access arguments using named accessors or or via the generic get() | ||
| 340 | print $ng->warning; | ||
| 341 | print $ng->get('critical'); | ||
| 342 | |||
| 343 | |||
| 344 | |||
| 345 | =head1 DESCRIPTION | ||
| 346 | |||
| 347 | Nagios::Plugin::Getopt is an OO perl module providing standardised and | ||
| 348 | simplified argument processing for Nagios plugins. It implements | ||
| 349 | a number of standard arguments itself (--help, --version, | ||
| 350 | --usage, --timeout, --verbose, and their short form counterparts), | ||
| 351 | produces standardised nagios plugin help output, and allows | ||
| 352 | additional arguments to be easily defined. | ||
| 353 | |||
| 354 | |||
| 355 | =head2 CONSTRUCTOR | ||
| 356 | |||
| 357 | # Instantiate object (usage and version are mandatory) | ||
| 358 | $ng = Nagios::Plugin::Getopt->new( | ||
| 359 | usage => 'Usage: %s --hello', | ||
| 360 | version => '0.01', | ||
| 361 | ); | ||
| 362 | |||
| 363 | The Nagios::Plugin::Getopt constructor accepts the following named | ||
| 364 | arguments: | ||
| 365 | |||
| 366 | =over 4 | ||
| 367 | |||
| 368 | =item usage (required) | ||
| 369 | |||
| 370 | Short usage message used with --usage/-? and with missing required | ||
| 371 | arguments, and included in the longer --help output. Can include | ||
| 372 | a '%s' sprintf placeholder which will be replaced with the plugin | ||
| 373 | name e.g. | ||
| 374 | |||
| 375 | usage => qq(Usage: %s -H <hostname> -p <ports> [-v]), | ||
| 376 | |||
| 377 | might be displayed as: | ||
| 378 | |||
| 379 | $ ./check_tcp_range --usage | ||
| 380 | Usage: check_tcp_range -H <hostname> -p <ports> [-v] | ||
| 381 | |||
| 382 | =item version (required) | ||
| 383 | |||
| 384 | Plugin version number, included in the --version/-V output, and in | ||
| 385 | the longer --help output. e.g. | ||
| 386 | |||
| 387 | $ ./check_tcp_range --version | ||
| 388 | check_tcp_range 0.2 [http://www.openfusion.com.au/labs/nagios/] | ||
| 389 | |||
| 390 | =item url | ||
| 391 | |||
| 392 | URL for info about this plugin, included in the --version/-V output, | ||
| 393 | and in the longer --help output (see preceding 'version' example). | ||
| 394 | |||
| 395 | =item blurb | ||
| 396 | |||
| 397 | Short plugin description, included in the longer --help output | ||
| 398 | (see below for an example). | ||
| 399 | |||
| 400 | =item license | ||
| 401 | |||
| 402 | License text, included in the longer --help output (see below for an | ||
| 403 | example). By default, this is set to the standard nagios plugins | ||
| 404 | GPL licence text: | ||
| 405 | |||
| 406 | This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY. | ||
| 407 | It may be used, redistributed and/or modified under the terms of the GNU | ||
| 408 | General Public Licence (see http://www.fsf.org/licensing/licenses/gpl.txt). | ||
| 409 | |||
| 410 | Provide your own to replace this text in the help output. | ||
| 411 | |||
| 412 | =item extra | ||
| 413 | |||
| 414 | Extra text to be appended at the end of the longer --help output. | ||
| 415 | |||
| 416 | =item plugin | ||
| 417 | |||
| 418 | Plugin name. This defaults to the basename of your plugin, which is | ||
| 419 | usually correct, but you can set it explicitly if not. | ||
| 420 | |||
| 421 | =item timeout | ||
| 422 | |||
| 423 | Timeout period in seconds, overriding the standard timeout default | ||
| 424 | (15 seconds). | ||
| 425 | |||
| 426 | =back | ||
| 427 | |||
| 428 | The full --help output has the following form: | ||
| 429 | |||
| 430 | version string | ||
| 431 | |||
| 432 | license string | ||
| 433 | |||
| 434 | blurb | ||
| 435 | |||
| 436 | usage string | ||
| 437 | |||
| 438 | options list | ||
| 439 | |||
| 440 | extra text | ||
| 441 | |||
| 442 | The 'blurb' and 'extra text' sections are omitted if not supplied. For | ||
| 443 | example: | ||
| 444 | |||
| 445 | $ ./check_tcp_range -h | ||
| 446 | check_tcp_range 0.2 [http://www.openfusion.com.au/labs/nagios/] | ||
| 447 | |||
| 448 | This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY. | ||
| 449 | It may be used, redistributed and/or modified under the terms of the GNU | ||
| 450 | General Public Licence (see http://www.fsf.org/licensing/licenses/gpl.txt). | ||
| 451 | |||
| 452 | This plugin tests arbitrary ranges/sets of tcp ports for a host. | ||
| 453 | |||
| 454 | Usage: check_tcp_range -H <hostname> -p <ports> [-v] | ||
| 455 | |||
| 456 | Options: | ||
| 457 | -h, --help | ||
| 458 | Print detailed help screen | ||
| 459 | -V, --version | ||
| 460 | Print version information | ||
| 461 | -H, --hostname=ADDRESS | ||
| 462 | Host name or IP address | ||
| 463 | -p, --ports=STRING | ||
| 464 | Port numbers to check. Format: comma-separated, colons or hyphens for ranges, | ||
| 465 | no spaces e.g. 8700:8705,8710-8715,8760 | ||
| 466 | -t, --timeout=INTEGER | ||
| 467 | Seconds before plugin times out (default: 15) | ||
| 468 | -v, --verbose | ||
| 469 | Show details for command-line debugging | ||
| 470 | |||
| 471 | |||
| 472 | =head2 ARGUMENTS | ||
| 473 | |||
| 474 | You can define arguments for your plugin using the arg() method, which | ||
| 475 | supports both named and positional arguments. In both cases | ||
| 476 | the 'spec' and 'help' arguments are required, while the 'default' | ||
| 477 | and 'required' arguments are optional: | ||
| 478 | |||
| 479 | # Define --hello argument (named parameters) | ||
| 480 | $ng->arg( | ||
| 481 | spec => 'hello=s', | ||
| 482 | help => "--hello\n Hello string", | ||
| 483 | required => 1, | ||
| 484 | ); | ||
| 485 | |||
| 486 | # Define --hello argument (positional parameters) | ||
| 487 | # Parameter order is 'spec', 'help', 'default', 'required?' | ||
| 488 | $ng->arg('hello=s', "--hello\n Hello string", undef, 1); | ||
| 489 | |||
| 490 | The 'spec' argument (the first argument in the positional variant) is a | ||
| 491 | L<Getopt::Long> argument specification. See L<Getopt::Long> for the details, | ||
| 492 | but basically it is a series of one or more argument names for this argument | ||
| 493 | (separated by '|'), suffixed with an '=<type>' indicator if the argument | ||
| 494 | takes a value. '=s' indicates a string argument; '=i' indicates an integer | ||
| 495 | argument; appending an '@' indicates multiple such arguments are accepted; | ||
| 496 | and so on. The following are some examples: | ||
| 497 | |||
| 498 | =over 4 | ||
| 499 | |||
| 500 | =item hello=s | ||
| 501 | |||
| 502 | =item hello|h=s | ||
| 503 | |||
| 504 | =item ports|port|p=i | ||
| 505 | |||
| 506 | =item exclude|X=s@ | ||
| 507 | |||
| 508 | =item verbose|v | ||
| 509 | |||
| 510 | =back | ||
| 511 | |||
| 512 | The 'help' argument is a string displayed in the --help option list output. | ||
| 513 | If the string contains a '%s' it will be formatted via L<sprintf> with the | ||
| 514 | 'default' as the argument i.e. | ||
| 515 | |||
| 516 | sprintf($help, $default) | ||
| 517 | |||
| 518 | A gotcha is that standard percentage signs also need to be escaped | ||
| 519 | (i.e. '%%') in this case. | ||
| 520 | |||
| 521 | The 'default' argument is the default value to be given to this parameter | ||
| 522 | if none is explicitly supplied. | ||
| 523 | |||
| 524 | The 'required' argument is a boolean used to indicate that this argument | ||
| 525 | is mandatory (Nagios::Plugin::Getopt will exit with your usage message and | ||
| 526 | a 'Missing argument' indicator if any required arguments are not supplied). | ||
| 527 | |||
| 528 | Note that --help lists your arguments in the order they are defined, so | ||
| 529 | you might want to order your arg() calls accordingly. | ||
| 530 | |||
| 531 | |||
| 532 | =head2 GETOPTS | ||
| 533 | |||
| 534 | The main parsing and processing functionality is provided by the getopts() | ||
| 535 | method, which takes no arguments: | ||
| 536 | |||
| 537 | # Parse and process arguments | ||
| 538 | $ng->getopts; | ||
| 539 | |||
| 540 | This parses the command line arguments passed to your plugin using | ||
| 541 | Getopt::Long and the builtin and provided argument specifications. | ||
| 542 | Flags and argument values are recorded within the object, and can | ||
| 543 | be accessed either using the generic get() accessor, or using named | ||
| 544 | accessors corresponding to your argument names. For example: | ||
| 545 | |||
| 546 | print $ng->get('hello'); | ||
| 547 | print $ng->hello(); | ||
| 548 | |||
| 549 | if ($ng->verbose) { | ||
| 550 | # ... | ||
| 551 | } | ||
| 552 | |||
| 553 | if ($ng->get('ports') =~ m/:/) { | ||
| 554 | # ... | ||
| 555 | } | ||
| 556 | |||
| 557 | Note that where you have defined alternate argument names, the first is | ||
| 558 | considered the citation form. All the builtin arguments are available | ||
| 559 | using their long variant names. | ||
| 560 | |||
| 561 | |||
| 562 | =head2 BUILTIN PROCESSING | ||
| 563 | |||
| 564 | The getopts() method also handles processing of the immediate builtin | ||
| 565 | arguments, namely --usage, --version, --help, as well as checking all | ||
| 566 | required arguments have been supplied, so you don't have to handle | ||
| 567 | those yourself. This means that your plugin will exit from the getopts() | ||
| 568 | call in these cases - if you want to catch that you can run getopts() | ||
| 569 | within an eval{}. | ||
| 570 | |||
| 571 | getopts() also sets up a default ALRM timeout handler so you can use an | ||
| 572 | |||
| 573 | alarm $ng->timeout; | ||
| 574 | |||
| 575 | around any blocking operations within your plugin (which you are free | ||
| 576 | to override if you want to use a custom timeout message). | ||
| 577 | |||
| 578 | |||
| 579 | =head1 SEE ALSO | ||
| 580 | |||
| 581 | Nagios::Plugin, Getopt::Long | ||
| 582 | |||
| 583 | |||
| 584 | =head1 AUTHOR | ||
| 585 | |||
| 586 | Gavin Carr <gavin@openfusion.com.au> | ||
| 587 | |||
| 588 | |||
| 589 | =head1 COPYRIGHT AND LICENSE | ||
| 590 | |||
| 591 | Copyright 2005-2006 Gavin Carr. All Rights Reserved. | ||
| 592 | |||
| 593 | This module is free software. It may be used, redistributed | ||
| 594 | and/or modified under either the terms of the Perl Artistic | ||
| 595 | License (see http://www.perl.com/perl/misc/Artistic.html) | ||
| 596 | or the GNU General Public Licence (see | ||
| 597 | http://www.fsf.org/licensing/licenses/gpl.txt). | ||
| 598 | |||
| 599 | =cut | ||
| 600 | |||
| 601 | # arch-tag: c917effc-7400-4ee5-a5d6-baa9316a3abf | ||
| 602 | # vim:smartindent:sw=2:et | ||
| 603 | |||
diff --git a/t/Nagios-Plugin-Getopt-01.t b/t/Nagios-Plugin-Getopt-01.t new file mode 100644 index 0000000..fad68e3 --- /dev/null +++ b/t/Nagios-Plugin-Getopt-01.t | |||
| @@ -0,0 +1,134 @@ | |||
| 1 | # Nagios::Plugin::Getopt basic tests | ||
| 2 | |||
| 3 | use strict; | ||
| 4 | |||
| 5 | use Test::More tests => 72; | ||
| 6 | BEGIN { use_ok('Nagios::Plugin::Getopt') }; | ||
| 7 | |||
| 8 | my %PARAM = ( | ||
| 9 | version => '0.01', | ||
| 10 | url => 'http://www.openfusion.com.au/labs/nagios/', | ||
| 11 | blurb => 'This plugin tests various stuff.', | ||
| 12 | usage => "Usage: %s -H <host> -w <warning_threshold> | ||
| 13 | -c <critical threshold>", | ||
| 14 | plugin => 'test_plugin', | ||
| 15 | ); | ||
| 16 | |||
| 17 | sub setup | ||
| 18 | { | ||
| 19 | # Instantiate object | ||
| 20 | my $ng = Nagios::Plugin::Getopt->new(%PARAM); | ||
| 21 | ok($ng, 'constructor ok'); | ||
| 22 | |||
| 23 | # Add argument - short form - arg spec, help text, default, required? | ||
| 24 | $ng->arg('warning|w=s' => | ||
| 25 | qq(-w, --warning=INTEGER\n Exit with WARNING status if less than INTEGER foobars are free), | ||
| 26 | 5); | ||
| 27 | |||
| 28 | # Add argument - named version | ||
| 29 | $ng->arg( | ||
| 30 | spec => 'critical|c=s', | ||
| 31 | help => qq(-c, --critical=INTEGER\n Exit with CRITICAL status if less than INTEGER foobars are free), | ||
| 32 | required => 1, | ||
| 33 | ); | ||
| 34 | |||
| 35 | return $ng; | ||
| 36 | } | ||
| 37 | |||
| 38 | my $ng; | ||
| 39 | |||
| 40 | # Simple usage (short and long args) | ||
| 41 | @ARGV = qw(-w 3 --critical 10 --timeout=12 --verbose); | ||
| 42 | $ng = setup; | ||
| 43 | $ng->getopts; | ||
| 44 | is($ng->warning, 3, 'warning set to 3'); | ||
| 45 | is($ng->critical, 10, 'critical set to 10'); | ||
| 46 | is($ng->timeout, 12, 'timeout set to 12'); | ||
| 47 | |||
| 48 | # Missing args | ||
| 49 | @ARGV = qw(); | ||
| 50 | $ng = setup; | ||
| 51 | ok(! defined eval { $ng->getopts }, 'getopts died on missing args'); | ||
| 52 | like($@, qr/Usage:/, 'usage message'); | ||
| 53 | like($@, qr/Missing arg/, 'missing arguments'); | ||
| 54 | is($ng->verbose, 0, 'verbose set to 0'); | ||
| 55 | # Missing critical | ||
| 56 | @ARGV = qw(-w0 -v); | ||
| 57 | $ng = setup; | ||
| 58 | ok(! defined eval { $ng->getopts }, 'getopts died on missing args'); | ||
| 59 | like($@, qr/Usage:/, 'usage message'); | ||
| 60 | like($@, qr/Missing argument: critical/, 'missing argument: critical'); | ||
| 61 | unlike($@, qr/Missing argument: warning/, 'no missing argument: warning'); | ||
| 62 | is($ng->warning, 0, 'warning set to 0'); | ||
| 63 | is($ng->critical, undef, 'critical undef'); | ||
| 64 | is($ng->timeout, 15, 'timeout set to default'); | ||
| 65 | is($ng->verbose, 1, 'verbose set to true'); | ||
| 66 | # Missing warning | ||
| 67 | @ARGV = qw(--critical=27 --timeout 17 --verbose); | ||
| 68 | $ng = setup; | ||
| 69 | $ng->getopts; | ||
| 70 | is($ng->warning, 5, 'warning 5 (default)'); | ||
| 71 | is($ng->critical, 27, 'critical set to 27'); | ||
| 72 | is($ng->timeout, 17, 'timeout set to 17'); | ||
| 73 | is($ng->verbose, 1, 'verbose set to true'); | ||
| 74 | |||
| 75 | # -? --usage | ||
| 76 | @ARGV = ( '-?' ); | ||
| 77 | $ng = setup; | ||
| 78 | ok(! defined eval { $ng->getopts }, 'getopts died on usage'); | ||
| 79 | like($@, qr/Usage:/, 'usage message'); | ||
| 80 | unlike($@, qr/Missing arg/, 'no missing arguments'); | ||
| 81 | @ARGV = ( '--usage' ); | ||
| 82 | $ng = setup; | ||
| 83 | ok(! defined eval { $ng->getopts }, 'getopts died on usage'); | ||
| 84 | like($@, qr/Usage:/, 'usage message'); | ||
| 85 | unlike($@, qr/Missing arg/, 'no missing arguments'); | ||
| 86 | |||
| 87 | # -V --version | ||
| 88 | @ARGV = ( '-V' ); | ||
| 89 | $ng = setup; | ||
| 90 | ok(! defined eval { $ng->getopts }, 'getopts died on version'); | ||
| 91 | like($@, qr/^$PARAM{plugin}/, 'version info includes plugin name'); | ||
| 92 | like($@, qr/$PARAM{version}/, 'version info includes version'); | ||
| 93 | like($@, qr/$PARAM{url}/, 'version info includes url'); | ||
| 94 | unlike($@, qr/Usage:/, 'no usage message'); | ||
| 95 | unlike($@, qr/Missing arg/, 'no missing arguments'); | ||
| 96 | @ARGV = ( '--version' ); | ||
| 97 | $ng = setup; | ||
| 98 | ok(! defined eval { $ng->getopts }, 'getopts died on version'); | ||
| 99 | like($@, qr/^$PARAM{plugin}/, 'version info includes plugin name'); | ||
| 100 | like($@, qr/$PARAM{version}/, 'version info includes version'); | ||
| 101 | like($@, qr/$PARAM{url}/, 'version info includes url'); | ||
| 102 | unlike($@, qr/Usage:/, 'no usage message'); | ||
| 103 | unlike($@, qr/Missing arg/, 'no missing arguments'); | ||
| 104 | |||
| 105 | # -h --help | ||
| 106 | @ARGV = ( '-h' ); | ||
| 107 | $ng = setup; | ||
| 108 | ok(! defined eval { $ng->getopts }, 'getopts died on help'); | ||
| 109 | like($@, qr/^$PARAM{plugin}/, 'help includes plugin name'); | ||
| 110 | like($@, qr/$PARAM{version}/, 'help includes version'); | ||
| 111 | like($@, qr/$PARAM{url}/, 'help includes url'); | ||
| 112 | like($@, qr/General Public Licence/, 'help includes licence'); | ||
| 113 | like($@, qr/$PARAM{blurb}/, 'help includes blurb'); | ||
| 114 | like($@, qr/Usage:/, 'help includes usage message'); | ||
| 115 | like($@, qr/--version/, 'help includes default options 1'); | ||
| 116 | like($@, qr/--verbose/, 'help includes default options 2'); | ||
| 117 | like($@, qr/--warning/, 'help includes custom option 1'); | ||
| 118 | like($@, qr/--critical/, 'help includes custom option 2'); | ||
| 119 | unlike($@, qr/Missing arg/, 'no missing arguments'); | ||
| 120 | @ARGV = ( '--help' ); | ||
| 121 | $ng = setup; | ||
| 122 | ok(! defined eval { $ng->getopts }, 'getopts died on help'); | ||
| 123 | like($@, qr/^$PARAM{plugin}/, 'help includes plugin name'); | ||
| 124 | like($@, qr/$PARAM{version}/, 'help includes version'); | ||
| 125 | like($@, qr/$PARAM{url}/, 'help includes url'); | ||
| 126 | like($@, qr/General Public Licence/, 'help includes licence'); | ||
| 127 | like($@, qr/$PARAM{blurb}/, 'help includes blurb'); | ||
| 128 | like($@, qr/Usage:/, 'help includes usage message'); | ||
| 129 | like($@, qr/--version/, 'help includes default options 1'); | ||
| 130 | like($@, qr/--verbose/, 'help includes default options 2'); | ||
| 131 | like($@, qr/--warning/, 'help includes custom option 1'); | ||
| 132 | like($@, qr/--critical/, 'help includes custom option 2'); | ||
| 133 | unlike($@, qr/Missing arg/, 'no missing arguments'); | ||
| 134 | |||
diff --git a/t/Nagios-Plugin-Getopt-02.t b/t/Nagios-Plugin-Getopt-02.t new file mode 100644 index 0000000..26e0293 --- /dev/null +++ b/t/Nagios-Plugin-Getopt-02.t | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | # Nagios::Plugin::Getopt timeout tests | ||
| 2 | |||
| 3 | use strict; | ||
| 4 | |||
| 5 | use Test::More tests => 14; | ||
| 6 | BEGIN { use_ok('Nagios::Plugin::Getopt') }; | ||
| 7 | |||
| 8 | my %PARAM = ( | ||
| 9 | version => '0.01', | ||
| 10 | url => 'http://www.openfusion.com.au/labs/nagios/', | ||
| 11 | blurb => 'This plugin tests various stuff.', | ||
| 12 | usage => "Usage: %s -H <host> -w <warning_threshold> | ||
| 13 | -c <critical threshold>", | ||
| 14 | plugin => 'test_plugin', | ||
| 15 | timeout => 18, | ||
| 16 | ); | ||
| 17 | |||
| 18 | sub setup | ||
| 19 | { | ||
| 20 | # Instantiate object | ||
| 21 | my $ng = Nagios::Plugin::Getopt->new(%PARAM); | ||
| 22 | ok($ng, 'constructor ok'); | ||
| 23 | return $ng; | ||
| 24 | } | ||
| 25 | |||
| 26 | my $ng; | ||
| 27 | |||
| 28 | # No args | ||
| 29 | @ARGV = qw(); | ||
| 30 | $ng = setup(); | ||
| 31 | $ng->getopts; | ||
| 32 | is($ng->timeout, 18, 'default timeout set to 18'); | ||
| 33 | |||
| 34 | # Check help message | ||
| 35 | @ARGV = ( '-h' ); | ||
| 36 | $ng = setup; | ||
| 37 | ok(! defined eval { $ng->getopts }, 'getopts died on help'); | ||
| 38 | like($@, qr/times out.*default: 18\b/i, 'help timeout changed to 18'); | ||
| 39 | |||
| 40 | # Explicit timeout | ||
| 41 | @ARGV = qw(--timeout=25 --verbose); | ||
| 42 | $ng = setup(); | ||
| 43 | $ng->getopts; | ||
| 44 | is($ng->timeout, 25, 'timeout changed to 25'); | ||
| 45 | |||
| 46 | # Explicit timeout | ||
| 47 | @ARGV = qw(-t10 --verbose); | ||
| 48 | $ng = setup(); | ||
| 49 | $ng->getopts; | ||
| 50 | is($ng->timeout, 10, 'timeout changed to 10'); | ||
| 51 | |||
| 52 | # Short timeout, test default timeout handler | ||
| 53 | @ARGV = qw(-t2 --verbose); | ||
| 54 | $ng = setup(); | ||
| 55 | $ng->getopts; | ||
| 56 | is($ng->timeout, 2, 'timeout changed to 2'); | ||
| 57 | alarm($ng->timeout); | ||
| 58 | # Loop | ||
| 59 | ok(! defined eval { 1 while 1 }, 'loop timed out'); | ||
| 60 | like($@, qr/UNKNOWN\b.*\btimed out/, 'default timeout handler ok'); | ||
| 61 | |||
