summaryrefslogtreecommitdiffstats
path: root/lib/Nagios
diff options
context:
space:
mode:
authorGavin Carr <gonzai@users.sourceforge.net>2006-08-30 01:20:41 +0000
committerGavin Carr <gonzai@users.sourceforge.net>2006-08-30 01:20:41 +0000
commita70a6ff5acf2a2b252328427293801ce0ff42888 (patch)
tree8d3b573f3abaaa68f4eec0cbae4afa739bdfb2a7 /lib/Nagios
parent96933fd2e1f53aff9c9ef26639fafe9a84ec754e (diff)
downloadmonitoring-plugin-perl-a70a6ff5acf2a2b252328427293801ce0ff42888.tar.gz
Add first-pass Nagios::Plugin::Getopt.
git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/Nagios-Plugin/trunk@1470 f882894a-f735-0410-b71e-b25c423dba1c
Diffstat (limited to 'lib/Nagios')
-rw-r--r--lib/Nagios/Plugin/Getopt.pm603
1 files changed, 603 insertions, 0 deletions
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
6package Nagios::Plugin::Getopt;
7
8use 5.005003;
9use strict;
10use File::Basename;
11use Getopt::Long qw(:config no_ignore_case bundling);
12use Carp;
13use Params::Validate qw(:all);
14use base qw(Class::Accessor);
15
16use vars qw($VERSION);
17$VERSION = '0.02';
18
19# Standard defaults
20my %DEFAULT = (
21 timeout => 15,
22 verbose => 0,
23 licence =>
24"This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY.
25It may be used, redistributed and/or modified under the terms of the GNU
26General Public Licence (see http://www.fsf.org/licensing/licenses/gpl.txt).",
27);
28# Standard arguments
29my @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
49my %DEFER_ARGS = map { $_ => 1 } qw(timeout verbose);
50
51# -------------------------------------------------------------------------
52# Private methods
53
54sub _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
65sub _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
75sub _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)
102sub _usage
103{
104 my $self = shift;
105 sprintf $self->_attr('usage'), $self->{_attr}->{plugin};
106}
107
108# Output for plugin -V
109sub _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
119sub _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
133sub _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
157sub _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
174sub _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
188sub 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)
219sub 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
254sub _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
283sub new
284{
285 my $class = shift;
286 my $self = bless {}, $class;
287 $self->_init(@_);
288}
289
290# -------------------------------------------------------------------------
291
2921;
293
294__END__
295
296=head1 NAME
297
298Nagios::Plugin::Getopt - OO perl module providing standardised argument
299processing for Nagios plugins
300
301
302=head1 VERSION
303
304This 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
347Nagios::Plugin::Getopt is an OO perl module providing standardised and
348simplified argument processing for Nagios plugins. It implements
349a number of standard arguments itself (--help, --version,
350--usage, --timeout, --verbose, and their short form counterparts),
351produces standardised nagios plugin help output, and allows
352additional 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
363The Nagios::Plugin::Getopt constructor accepts the following named
364arguments:
365
366=over 4
367
368=item usage (required)
369
370Short usage message used with --usage/-? and with missing required
371arguments, and included in the longer --help output. Can include
372a '%s' sprintf placeholder which will be replaced with the plugin
373name e.g.
374
375 usage => qq(Usage: %s -H <hostname> -p <ports> [-v]),
376
377might 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
384Plugin version number, included in the --version/-V output, and in
385the 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
392URL for info about this plugin, included in the --version/-V output,
393and in the longer --help output (see preceding 'version' example).
394
395=item blurb
396
397Short plugin description, included in the longer --help output
398(see below for an example).
399
400=item license
401
402License text, included in the longer --help output (see below for an
403example). By default, this is set to the standard nagios plugins
404GPL 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
410Provide your own to replace this text in the help output.
411
412=item extra
413
414Extra text to be appended at the end of the longer --help output.
415
416=item plugin
417
418Plugin name. This defaults to the basename of your plugin, which is
419usually correct, but you can set it explicitly if not.
420
421=item timeout
422
423Timeout period in seconds, overriding the standard timeout default
424(15 seconds).
425
426=back
427
428The 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
442The 'blurb' and 'extra text' sections are omitted if not supplied. For
443example:
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
474You can define arguments for your plugin using the arg() method, which
475supports both named and positional arguments. In both cases
476the 'spec' and 'help' arguments are required, while the 'default'
477and '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
490The 'spec' argument (the first argument in the positional variant) is a
491L<Getopt::Long> argument specification. See L<Getopt::Long> for the details,
492but 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
494takes a value. '=s' indicates a string argument; '=i' indicates an integer
495argument; appending an '@' indicates multiple such arguments are accepted;
496and 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
512The 'help' argument is a string displayed in the --help option list output.
513If 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
518A gotcha is that standard percentage signs also need to be escaped
519(i.e. '%%') in this case.
520
521The 'default' argument is the default value to be given to this parameter
522if none is explicitly supplied.
523
524The 'required' argument is a boolean used to indicate that this argument
525is mandatory (Nagios::Plugin::Getopt will exit with your usage message and
526a 'Missing argument' indicator if any required arguments are not supplied).
527
528Note that --help lists your arguments in the order they are defined, so
529you might want to order your arg() calls accordingly.
530
531
532=head2 GETOPTS
533
534The main parsing and processing functionality is provided by the getopts()
535method, which takes no arguments:
536
537 # Parse and process arguments
538 $ng->getopts;
539
540This parses the command line arguments passed to your plugin using
541Getopt::Long and the builtin and provided argument specifications.
542Flags and argument values are recorded within the object, and can
543be accessed either using the generic get() accessor, or using named
544accessors 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
557Note that where you have defined alternate argument names, the first is
558considered the citation form. All the builtin arguments are available
559using their long variant names.
560
561
562=head2 BUILTIN PROCESSING
563
564The getopts() method also handles processing of the immediate builtin
565arguments, namely --usage, --version, --help, as well as checking all
566required arguments have been supplied, so you don't have to handle
567those yourself. This means that your plugin will exit from the getopts()
568call in these cases - if you want to catch that you can run getopts()
569within an eval{}.
570
571getopts() also sets up a default ALRM timeout handler so you can use an
572
573 alarm $ng->timeout;
574
575around any blocking operations within your plugin (which you are free
576to override if you want to use a custom timeout message).
577
578
579=head1 SEE ALSO
580
581Nagios::Plugin, Getopt::Long
582
583
584=head1 AUTHOR
585
586Gavin Carr <gavin@openfusion.com.au>
587
588
589=head1 COPYRIGHT AND LICENSE
590
591Copyright 2005-2006 Gavin Carr. All Rights Reserved.
592
593This module is free software. It may be used, redistributed
594and/or modified under either the terms of the Perl Artistic
595License (see http://www.perl.com/perl/misc/Artistic.html)
596or the GNU General Public Licence (see
597http://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