diff options
-rw-r--r-- | MANIFEST | 24 | ||||
-rw-r--r-- | META.yml | 8 | ||||
-rw-r--r-- | Makefile.PL | 8 | ||||
-rw-r--r-- | lib/Nagios/Plugin/Getopt.pm | 162 |
4 files changed, 189 insertions, 13 deletions
@@ -12,9 +12,33 @@ t/Nagios-Plugin-Functions-01.t | |||
12 | t/Nagios-Plugin-Functions-02.t | 12 | t/Nagios-Plugin-Functions-02.t |
13 | t/Nagios-Plugin-Getopt-01.t | 13 | t/Nagios-Plugin-Getopt-01.t |
14 | t/Nagios-Plugin-Getopt-02.t | 14 | t/Nagios-Plugin-Getopt-02.t |
15 | t/Nagios-Plugin-Getopt-03.t | ||
15 | t/Nagios-Plugin-Performance.t | 16 | t/Nagios-Plugin-Performance.t |
16 | t/Nagios-Plugin-Range.t | 17 | t/Nagios-Plugin-Range.t |
17 | t/Nagios-Plugin-Threshold.t | 18 | t/Nagios-Plugin-Threshold.t |
19 | t/npg03/ | ||
20 | t/npg03/README | ||
21 | t/npg03/expected/ | ||
22 | t/npg03/expected/00_basic | ||
23 | t/npg03/expected/01_override1 | ||
24 | t/npg03/expected/02_override2 | ||
25 | t/npg03/expected/05_singlechar1 | ||
26 | t/npg03/expected/06_singlechar2 | ||
27 | t/npg03/expected/07_singlechar3 | ||
28 | t/npg03/expected/09_funnystuff | ||
29 | t/npg03/expected/12_nosection_implicit | ||
30 | t/npg03/input/ | ||
31 | t/npg03/input/00_basic | ||
32 | t/npg03/input/01_override1 | ||
33 | t/npg03/input/02_override2 | ||
34 | t/npg03/input/05_singlechar1 | ||
35 | t/npg03/input/06_singlechar2 | ||
36 | t/npg03/input/07_singlechar3 | ||
37 | t/npg03/input/09_funnystuff | ||
38 | t/npg03/input/12_nosection_implicit | ||
39 | t/npg03/input/13_nosection_explicit_dies | ||
40 | t/npg03/input/14_badsection_dies | ||
41 | t/npg03/plugins.cfg | ||
18 | lib/Nagios/Plugin.pm | 42 | lib/Nagios/Plugin.pm |
19 | lib/Nagios/Plugin/Performance.pm | 43 | lib/Nagios/Plugin/Performance.pm |
20 | lib/Nagios/Plugin/Range.pm | 44 | lib/Nagios/Plugin/Range.pm |
@@ -6,9 +6,13 @@ version_from: lib/Nagios/Plugin/Functions.pm | |||
6 | installdirs: site | 6 | installdirs: site |
7 | requires: | 7 | requires: |
8 | Carp: 0 | 8 | Carp: 0 |
9 | Class::Accessor: 0.22 | 9 | Class::Accessor: 0 |
10 | Params::Validate: 0.24 | 10 | Params::Validate: 0 |
11 | Test::More: 0.62 | 11 | Test::More: 0.62 |
12 | Config::Tiny: 0 | ||
13 | File::Spec: 0 | ||
14 | File::Basename: | ||
15 | IO::File: | ||
12 | 16 | ||
13 | distribution_type: module | 17 | distribution_type: module |
14 | generated_by: ExtUtils::MakeMaker version 6.17 | 18 | generated_by: ExtUtils::MakeMaker version 6.17 |
diff --git a/Makefile.PL b/Makefile.PL index f7f1131..63b36da 100644 --- a/Makefile.PL +++ b/Makefile.PL | |||
@@ -6,11 +6,15 @@ WriteMakefile( | |||
6 | NAME => 'Nagios::Plugin', | 6 | NAME => 'Nagios::Plugin', |
7 | VERSION_FROM => 'lib/Nagios/Plugin/Functions.pm', # finds $VERSION | 7 | VERSION_FROM => 'lib/Nagios/Plugin/Functions.pm', # finds $VERSION |
8 | PREREQ_PM => { | 8 | PREREQ_PM => { |
9 | Params::Validate => 0.24, | 9 | Params::Validate => 0, |
10 | Class::Accessor => 0.22, | 10 | Class::Accessor => 0, |
11 | Test::More => 0.62, | 11 | Test::More => 0.62, |
12 | Carp => 0, | 12 | Carp => 0, |
13 | Test::Exception => 0, | 13 | Test::Exception => 0, |
14 | Config::Tiny => 0, | ||
15 | File::Spec => 0, | ||
16 | File::Basename => 0, | ||
17 | IO::File => 0, | ||
14 | }, # e.g., Module::Name => 1.1 | 18 | }, # e.g., Module::Name => 1.1 |
15 | ($] >= 5.005 ? ## Add these new keywords supported since 5.005 | 19 | ($] >= 5.005 ? ## Add these new keywords supported since 5.005 |
16 | (ABSTRACT_FROM => 'lib/Nagios/Plugin.pm', # retrieve abstract from module | 20 | (ABSTRACT_FROM => 'lib/Nagios/Plugin.pm', # retrieve abstract from module |
diff --git a/lib/Nagios/Plugin/Getopt.pm b/lib/Nagios/Plugin/Getopt.pm index bbf1fc9..806a6a0 100644 --- a/lib/Nagios/Plugin/Getopt.pm +++ b/lib/Nagios/Plugin/Getopt.pm | |||
@@ -10,12 +10,15 @@ use File::Basename; | |||
10 | use Getopt::Long qw(:config no_ignore_case bundling); | 10 | use Getopt::Long qw(:config no_ignore_case bundling); |
11 | use Carp; | 11 | use Carp; |
12 | use Params::Validate qw(:all); | 12 | use Params::Validate qw(:all); |
13 | use Config::Tiny; | ||
13 | use base qw(Class::Accessor); | 14 | use base qw(Class::Accessor); |
14 | 15 | ||
15 | use Nagios::Plugin::Functions; | 16 | use Nagios::Plugin::Functions; |
16 | use vars qw($VERSION); | 17 | use vars qw($VERSION $DEFAULT_CONFIG_FILE); |
17 | $VERSION = $Nagios::Plugin::Functions::VERSION; | 18 | $VERSION = $Nagios::Plugin::Functions::VERSION; |
18 | 19 | ||
20 | $DEFAULT_CONFIG_FILE = '/etc/nagios/plugins.cfg'; | ||
21 | |||
19 | # Standard defaults | 22 | # Standard defaults |
20 | my %DEFAULT = ( | 23 | my %DEFAULT = ( |
21 | timeout => 15, | 24 | timeout => 15, |
@@ -36,6 +39,9 @@ my @ARGS = ({ | |||
36 | spec => 'version|V', | 39 | spec => 'version|V', |
37 | help => "-V, --version\n Print version information", | 40 | help => "-V, --version\n Print version information", |
38 | }, { | 41 | }, { |
42 | spec => 'default-opts:s@', | ||
43 | help => "--default-opts=[<section>[@<config_file>]]\n Section and/or config_file from which to load default options (may repeat)", | ||
44 | }, { | ||
39 | spec => 'timeout|t=i', | 45 | spec => 'timeout|t=i', |
40 | help => "-t, --timeout=INTEGER\n Seconds before plugin times out (default: %s)", | 46 | help => "-t, --timeout=INTEGER\n Seconds before plugin times out (default: %s)", |
41 | default => $DEFAULT{timeout}, | 47 | default => $DEFAULT{timeout}, |
@@ -140,7 +146,7 @@ sub _process_specs_getopt_long | |||
140 | # Setup names and defaults | 146 | # Setup names and defaults |
141 | my $spec = $arg->{spec}; | 147 | my $spec = $arg->{spec}; |
142 | # Use first arg as name (like Getopt::Long does) | 148 | # Use first arg as name (like Getopt::Long does) |
143 | $spec =~ s/=\w+$//; | 149 | $spec =~ s/[=:].*$//; |
144 | my $name = (split /\s*\|\s*/, $spec)[0]; | 150 | my $name = (split /\s*\|\s*/, $spec)[0]; |
145 | $arg->{name} = $name; | 151 | $arg->{name} = $name; |
146 | if (defined $self->{$name}) { | 152 | if (defined $self->{$name}) { |
@@ -182,6 +188,135 @@ sub _process_opts | |||
182 | } | 188 | } |
183 | 189 | ||
184 | # ------------------------------------------------------------------------- | 190 | # ------------------------------------------------------------------------- |
191 | # Default opts methods | ||
192 | |||
193 | sub _load_config_section | ||
194 | { | ||
195 | my $self = shift; | ||
196 | my ($section, $file, $flags) = @_; | ||
197 | $section ||= $self->{_attr}->{plugin}; | ||
198 | $file ||= $DEFAULT_CONFIG_FILE; | ||
199 | |||
200 | $self->_die("Cannot find config file '$file'") if $flags->{fatal} && ! -f $file; | ||
201 | |||
202 | my $Config = Config::Tiny->read($file); | ||
203 | $self->_die("Cannot read config file '$file'") unless defined $Config; | ||
204 | |||
205 | $self->_die("Invalid section '$section' in config file '$file'") | ||
206 | if $flags->{fatal} && ! exists $Config->{$section}; | ||
207 | |||
208 | return $Config->{$section}; | ||
209 | } | ||
210 | |||
211 | # Helper method to setup a hash of spec definitions for _cmdline | ||
212 | sub _setup_spec_index | ||
213 | { | ||
214 | my $self = shift; | ||
215 | return if defined $self->{_spec}; | ||
216 | $self->{_spec} = { map { $_->{name} => $_->{spec} } @{$self->{_args}} }; | ||
217 | } | ||
218 | |||
219 | # Quote values that require it | ||
220 | sub _cmdline_value | ||
221 | { | ||
222 | my $self = shift; | ||
223 | local $_ = shift; | ||
224 | if (m/\s/ && (m/^[^"']/ || m/[^"']$/)) { | ||
225 | return qq("$_"); | ||
226 | } | ||
227 | elsif ($_ eq '') { | ||
228 | return q(""); | ||
229 | } | ||
230 | else { | ||
231 | return $_; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | # Helper method to format key/values in $hash in a quasi-commandline format | ||
236 | sub _cmdline | ||
237 | { | ||
238 | my $self = shift; | ||
239 | my ($hash) = @_; | ||
240 | $hash ||= $self; | ||
241 | |||
242 | $self->_setup_spec_index; | ||
243 | |||
244 | my @args = (); | ||
245 | for my $key (sort keys %$hash) { | ||
246 | # Skip internal keys | ||
247 | next if $key =~ m/^_/; | ||
248 | |||
249 | # Skip defaults and internals | ||
250 | next if exists $DEFAULT{$key} && $hash->{$key} eq $DEFAULT{$key}; | ||
251 | next if grep { $key eq $_ } qw(help usage version default-opts); | ||
252 | next unless defined $hash->{$key}; | ||
253 | |||
254 | # Render arg | ||
255 | my $spec = $self->{_spec}->{$key} || ''; | ||
256 | if ($spec =~ m/[=:].+$/) { | ||
257 | # Arg takes value - may be a scalar or an arrayref | ||
258 | for my $value (ref $hash->{$key} eq 'ARRAY' ? @{$hash->{$key}} : ( $hash->{$key} )) { | ||
259 | $value = $self->_cmdline_value($value); | ||
260 | if (length($key) > 1) { | ||
261 | push @args, sprintf "--%s=%s", $key, $value; | ||
262 | } | ||
263 | else { | ||
264 | push @args, "-$key", $value; | ||
265 | } | ||
266 | } | ||
267 | } | ||
268 | |||
269 | else { | ||
270 | # Flag - render long or short based on option length | ||
271 | push @args, (length($key) > 1 ? '--' : '-') . $key; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | return wantarray ? @args : join(' ', @args); | ||
276 | } | ||
277 | |||
278 | # Process and load default-opts sections | ||
279 | sub _process_default_opts | ||
280 | { | ||
281 | my $self = shift; | ||
282 | my ($args) = @_; | ||
283 | |||
284 | my $defopts_list = $args->{'default-opts'}; | ||
285 | my $defopts_explicit = 1; | ||
286 | |||
287 | # If no default_opts defined, force one implicitly | ||
288 | if (! $defopts_list) { | ||
289 | $defopts_list = [ '' ]; | ||
290 | $defopts_explicit = 0; | ||
291 | } | ||
292 | |||
293 | my @sargs = (); | ||
294 | for my $defopts (@$defopts_list) { | ||
295 | $defopts ||= $self->{_attr}->{plugin}; | ||
296 | my $section = $defopts; | ||
297 | my $file = ''; | ||
298 | |||
299 | # Parse section@file | ||
300 | if ($defopts =~ m/^(\w*)@(.*?)\s*$/) { | ||
301 | $section = $1; | ||
302 | $file = $2; | ||
303 | } | ||
304 | |||
305 | # Load section args | ||
306 | my $shash = $self->_load_config_section($section, $file, { fatal => $defopts_explicit }); | ||
307 | |||
308 | # Turn $shash into a series of commandline-like arguments | ||
309 | push @sargs, $self->_cmdline($shash); | ||
310 | } | ||
311 | |||
312 | # Reset ARGV to default-opts + original | ||
313 | @ARGV = ( @sargs, @{$self->{_attr}->{argv}} ); | ||
314 | |||
315 | printf "[default-opts] %s %s\n", $self->{_attr}->{plugin}, join(' ', @ARGV) | ||
316 | if $args->{verbose} && $args->{verbose} >= 3; | ||
317 | } | ||
318 | |||
319 | # ------------------------------------------------------------------------- | ||
185 | # Public methods | 320 | # Public methods |
186 | 321 | ||
187 | # Define plugin argument | 322 | # Define plugin argument |
@@ -223,10 +358,21 @@ sub getopts | |||
223 | # Collate spec arguments for Getopt::Long | 358 | # Collate spec arguments for Getopt::Long |
224 | my @opt_array = $self->_process_specs_getopt_long; | 359 | my @opt_array = $self->_process_specs_getopt_long; |
225 | 360 | ||
361 | # Capture original @ARGV (for default-opts games) | ||
362 | $self->{_attr}->{argv} = [ @ARGV ]; | ||
363 | |||
226 | # Call GetOptions using @opt_array | 364 | # Call GetOptions using @opt_array |
227 | my $ok = GetOptions($self, @opt_array); | 365 | my $args1 = {}; |
366 | my $ok = GetOptions($args1, @opt_array); | ||
367 | # Invalid options - give usage message and exit | ||
368 | $self->_die($self->_usage) unless $ok; | ||
228 | 369 | ||
229 | # Invalid options - given usage message and exit | 370 | # Process default-opts |
371 | $self->_process_default_opts($args1); | ||
372 | |||
373 | # Call GetOptions again, this time including default-opts | ||
374 | $ok = GetOptions($self, @opt_array); | ||
375 | # Invalid options - give usage message and exit | ||
230 | $self->_die($self->_usage) unless $ok; | 376 | $self->_die($self->_usage) unless $ok; |
231 | 377 | ||
232 | # Process immediate options (possibly exiting) | 378 | # Process immediate options (possibly exiting) |
@@ -264,6 +410,7 @@ sub _init | |||
264 | plugin => { default => $plugin }, | 410 | plugin => { default => $plugin }, |
265 | blurb => 0, | 411 | blurb => 0, |
266 | extra => 0, | 412 | extra => 0, |
413 | 'default-opts' => 0, | ||
267 | license => { default => $DEFAULT{license} }, | 414 | license => { default => $DEFAULT{license} }, |
268 | timeout => { default => $DEFAULT{timeout} }, | 415 | timeout => { default => $DEFAULT{timeout} }, |
269 | }); | 416 | }); |
@@ -295,11 +442,8 @@ __END__ | |||
295 | 442 | ||
296 | =head1 NAME | 443 | =head1 NAME |
297 | 444 | ||
298 | Nagios::Plugin::Getopt - OO perl module providing standardised argument processing for Nagios plugins | 445 | Nagios::Plugin::Getopt - OO perl module providing standardised argument |
299 | 446 | processing for Nagios plugins | |
300 | =head1 VERSION | ||
301 | |||
302 | This documentation applies to version 0.01 of Nagios::Plugin::Getopt. | ||
303 | 447 | ||
304 | 448 | ||
305 | =head1 SYNOPSIS | 449 | =head1 SYNOPSIS |