From b418181dfe80dd75169b6e8a619ac1932155dea2 Mon Sep 17 00:00:00 2001 From: Sven Nierlein Date: Mon, 20 Jan 2014 00:54:34 +0100 Subject: renamed module into Monitoring::Plugin since the complete monitoring team has been renamed, we also rename this module. Signed-off-by: Sven Nierlein --- lib/Nagios/Plugin/Config.pm | 174 -------- lib/Nagios/Plugin/ExitResult.pm | 67 --- lib/Nagios/Plugin/Functions.pm | 446 -------------------- lib/Nagios/Plugin/Getopt.pm | 873 --------------------------------------- lib/Nagios/Plugin/Performance.pm | 294 ------------- lib/Nagios/Plugin/Range.pm | 169 -------- lib/Nagios/Plugin/Threshold.pm | 134 ------ 7 files changed, 2157 deletions(-) delete mode 100644 lib/Nagios/Plugin/Config.pm delete mode 100644 lib/Nagios/Plugin/ExitResult.pm delete mode 100644 lib/Nagios/Plugin/Functions.pm delete mode 100644 lib/Nagios/Plugin/Getopt.pm delete mode 100644 lib/Nagios/Plugin/Performance.pm delete mode 100644 lib/Nagios/Plugin/Range.pm delete mode 100644 lib/Nagios/Plugin/Threshold.pm (limited to 'lib/Nagios/Plugin') diff --git a/lib/Nagios/Plugin/Config.pm b/lib/Nagios/Plugin/Config.pm deleted file mode 100644 index dd270e9..0000000 --- a/lib/Nagios/Plugin/Config.pm +++ /dev/null @@ -1,174 +0,0 @@ -package Nagios::Plugin::Config; - -use strict; -use Carp; -use File::Spec; -use base qw(Config::Tiny); - -my $FILENAME1 = 'plugins.ini'; -my $FILENAME2 = 'nagios-plugins.ini'; -my $CURRENT_FILE = undef; - -# Config paths ending in nagios (search for $FILENAME1) -my @NAGIOS_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{NAGIOS_CONFIG_PATH}) { - for (split /:/, $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; - } - } - for (@NAGIOS_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; - } - } - - # Use die instead of croak, so we can pass a clean message downstream - die "Cannot find '$FILENAME1' or '$FILENAME2' 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 np_getfile { return $CURRENT_FILE; } - -1; - -=head1 NAME - -Nagios::Plugin::Config - read nagios plugin .ini style config files - -=head1 SYNOPSIS - - # Read given nagios plugin config file - $Config = Nagios::Plugin::Config->read( '/etc/nagios/plugins.ini' ); - - # Search for and read default nagios plugin config file - $Config = Nagios::Plugin::Config->read(); - - # Access sections and properties (returns scalars or arrayrefs) - $rootproperty = $Config->{_}->{rootproperty}; - $one = $Config->{section}->{one}; - $Foo = $Config->{section}->{Foo}; - -=head1 DESCRIPTION - -Nagios::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 - -Nagios::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 AUTHORS - -This code is maintained by the Nagios Plugin Development Team: -L. - - -=head1 COPYRIGHT and LICENCE - -Copyright (C) 2006-2007 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 - diff --git a/lib/Nagios/Plugin/ExitResult.pm b/lib/Nagios/Plugin/ExitResult.pm deleted file mode 100644 index b161e9e..0000000 --- a/lib/Nagios/Plugin/ExitResult.pm +++ /dev/null @@ -1,67 +0,0 @@ -# Tiny helper class to return both output and return_code when testing - -package Nagios::Plugin::ExitResult; - -use strict; - -# 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 - -Nagios::Plugin::ExitResult - Helper class for returning both output and -return codes when testing. - -=head1 SYNOPSIS - - use Test::More; - use Nagios::Plugin::Functions; - - # In a test file somewhere - Nagios::Plugin::Functions::_fake_exit(1); - - # Later ... - $e = nagios_exit( CRITICAL, 'aiiii ...' ); - print $e->message; - print $e->return_code; - - # NP::ExitResult also stringifies to the message output - like(nagios_exit( WARNING, 'foobar'), qr/^foo/, 'matches!'); - - - -=head1 DESCRIPTION - -Nagios::Plugin::ExitResult is a tiny helper class intended for use -when testing other Nagios::Plugin modules. A Nagios::Plugin::ExitResult -object is returned by nagios_exit() and friends when -Nagios::Plugin::Functions::_fake_exit has been set, instead of doing a -conventional print + exit. - -=head1 AUTHOR - -Gavin Carr , Egavin@openfusion.com.auE - -=head1 COPYRIGHT AND LICENSE - -Copyright (C) 2006 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 diff --git a/lib/Nagios/Plugin/Functions.pm b/lib/Nagios/Plugin/Functions.pm deleted file mode 100644 index 14fe661..0000000 --- a/lib/Nagios/Plugin/Functions.pm +++ /dev/null @@ -1,446 +0,0 @@ -# Functional interface to basic Nagios::Plugin constants, exports, -# and functions - -package Nagios::Plugin::Functions; - -use 5.006; - -use strict; -use warnings; -use File::Basename; -use Params::Validate qw(:types validate); -use Math::Calc::Units; - -# Remember to update Nagios::Plugins as well -our $VERSION = "0.36"; - -our @STATUS_CODES = qw(OK WARNING CRITICAL UNKNOWN DEPENDENT); - -require Exporter; -our @ISA = qw(Exporter); -our @EXPORT = (@STATUS_CODES, qw(nagios_exit nagios_die check_messages)); -our @EXPORT_OK = qw(%ERRORS %STATUS_TEXT @STATUS_CODES get_shortname max_state max_state_alt convert $value_re); -our %EXPORT_TAGS = ( - all => [ @EXPORT, @EXPORT_OK ], - codes => [ @STATUS_CODES ], - functions => [ qw(nagios_exit nagios_die check_messages max_state max_state_alt convert) ], -); - -use constant OK => 0; -use constant WARNING => 1; -use constant CRITICAL => 2; -use constant UNKNOWN => 3; -use constant DEPENDENT => 4; - -our %ERRORS = ( - 'OK' => OK, - 'WARNING' => WARNING, - 'CRITICAL' => CRITICAL, - 'UNKNOWN' => UNKNOWN, - 'DEPENDENT' => DEPENDENT, -); - -our %STATUS_TEXT = reverse %ERRORS; - -my $value = qr/[-+]?[\d\.]+/; -our $value_re = qr/$value(?:e$value)?/; - -# _fake_exit flag and accessor/mutator, for testing -my $_fake_exit = 0; -sub _fake_exit { @_ ? $_fake_exit = shift : $_fake_exit }; - -# _use_die flag and accessor/mutator, so exceptions can be raised correctly -my $_use_die = 0; -sub _use_die { @_ ? $_use_die = shift : $_use_die }; - -sub get_shortname { - my $arg = shift; - - my $shortname = undef; - - return $arg->{shortname} if (defined($arg->{shortname})); - $shortname = $arg->{plugin} if (defined( $arg->{plugin})); - - $shortname = uc basename($shortname || $ENV{NAGIOS_PLUGIN} || $0); - $shortname =~ s/^CHECK_(?:BY_)?//; # Remove any leading CHECK_[BY_] - $shortname =~ s/\..*$//; # Remove any trailing suffix - return $shortname; -} - -sub max_state { - return CRITICAL if grep { $_ == CRITICAL } @_; - return WARNING if grep { $_ == WARNING } @_; - return OK if grep { $_ == OK } @_; - return UNKNOWN if grep { $_ == UNKNOWN } @_; - return DEPENDENT if grep { $_ == DEPENDENT } @_; - return UNKNOWN; -} - -sub max_state_alt { - return CRITICAL if grep { $_ == CRITICAL } @_; - return WARNING if grep { $_ == WARNING } @_; - return UNKNOWN if grep { $_ == UNKNOWN } @_; - return DEPENDENT if grep { $_ == DEPENDENT } @_; - return OK if grep { $_ == OK } @_; - return UNKNOWN; -} - -# nagios_exit( $code, $message ) -sub nagios_exit { - my ($code, $message, $arg) = @_; - - # Handle named parameters - if (defined $code && ($code eq 'return_code' || $code eq 'message')) { - # Remove last argument if odd no and last is ref - if (int(@_ / 2) != @_ / 2 && ref $_[$#_]) { - $arg = pop @_; - } else { - undef $arg; - } - my %arg = @_; - $code = $arg{return_code}; - $message = $arg{message}; - } - $arg ||= {}; - - # Handle string codes - $code = $ERRORS{$code} if defined $code && exists $ERRORS{$code}; - - # Set defaults - $code = UNKNOWN unless defined $code && exists $STATUS_TEXT{$code}; - $message = '' unless defined $message; - if (ref $message && ref $message eq 'ARRAY') { - $message = join(' ', map { chomp; $_ } @$message); - } - else { - chomp $message; - } - - # Setup output - my $output = "$STATUS_TEXT{$code}"; - $output .= " - $message" if defined $message && $message ne ''; - my $shortname = ($arg->{plugin} ? $arg->{plugin}->shortname : undef); - $shortname ||= get_shortname(); # Should happen only if funnctions are called directly - $output = "$shortname $output" if $shortname; - if ($arg->{plugin}) { - my $plugin = $arg->{plugin}; - $output .= " | ". $plugin->all_perfoutput - if $plugin->perfdata && $plugin->all_perfoutput; - } - $output .= "\n"; - - # Don't actually exit if _fake_exit set - if ($_fake_exit) { - require Nagios::Plugin::ExitResult; - return Nagios::Plugin::ExitResult->new($code, $output); - } - - _nagios_exit($code, $output); -} - -sub _nagios_exit { - my ($code, $output) = @_; - # Print output and exit; die if flag set and called via a die in stack backtrace - if ($_use_die) { - for (my $i = 0;; $i++) { - @_ = caller($i); - last unless @_; - if ($_[3] =~ m/die/) { - $! = $code; - die($output); - } - } - } - print $output; - exit $code; -} - -# nagios_die( $message, [ $code ]) OR nagios_die( $code, $message ) -# Default $code: UNKNOWN -sub nagios_die { - my ($arg1, $arg2, $rest) = @_; - - # Named parameters - if (defined $arg1 && ($arg1 eq 'return_code' || $arg1 eq 'message')) { - return nagios_exit(@_); - } - - # ($code, $message) - elsif (defined $arg1 && (exists $ERRORS{$arg1} || exists $STATUS_TEXT{$arg1})) { - return nagios_exit(@_); - } - - # ($message, $code) - elsif (defined $arg2 && (exists $ERRORS{$arg2} || exists $STATUS_TEXT{$arg2})) { - return nagios_exit($arg2, $arg1, $rest); - } - - # Else just assume $arg1 is the message and hope for the best - else { - return nagios_exit( UNKNOWN, $arg1, $arg2 ); - } -} - -# For backwards compatibility -sub die { nagios_die(@_); } - - -# ------------------------------------------------------------------------ -# Utility functions - -# Simple wrapper around Math::Calc::Units::convert -sub convert -{ - my ($value, $from, $to) = @_; - my ($newval) = Math::Calc::Units::convert("$value $from", $to, 'exact'); - return $newval; -} - -# ------------------------------------------------------------------------ -# check_messages - return a status and/or message based on a set of -# message arrays. -# Returns a nagios status code in scalar context. -# Returns a code and a message in list context. -# The message is join($join, @array) for the relevant array for the code, -# or join($join_all, $message) for all arrays if $join_all is set. -sub check_messages { - my %arg = validate( @_, { - critical => { type => ARRAYREF }, - warning => { type => ARRAYREF }, - ok => { type => ARRAYREF | SCALAR, optional => 1 }, - 'join' => { default => ' ' }, - join_all => 0, - }); - $arg{join} = ' ' unless defined $arg{join}; - - # Decide $code - my $code = OK; - $code ||= CRITICAL if @{$arg{critical}}; - $code ||= WARNING if @{$arg{warning}}; - return $code unless wantarray; - - # Compose message - my $message = ''; - if ($arg{join_all}) { - $message = join( $arg{join_all}, - map { @$_ ? join( $arg{'join'}, @$_) : () } - $arg{critical}, - $arg{warning}, - $arg{ok} ? (ref $arg{ok} ? $arg{ok} : [ $arg{ok} ]) : [] - ); - } - - else { - $message ||= join( $arg{'join'}, @{$arg{critical}} ) - if $code == CRITICAL; - $message ||= join( $arg{'join'}, @{$arg{warning}} ) - if $code == WARNING; - $message ||= ref $arg{ok} ? join( $arg{'join'}, @{$arg{ok}} ) : $arg{ok} - if $arg{ok}; - } - - return ($code, $message); -} - -# ------------------------------------------------------------------------ - -1; - -# vim:sw=4:sm:et - -__END__ - -=head1 NAME - -Nagios::Plugin::Functions - functions to simplify the creation of -Nagios plugins - -=head1 SYNOPSIS - - # Constants OK, WARNING, CRITICAL, and UNKNOWN exported by default - use Nagios::Plugin::Functions; - - # nagios_exit( CODE, $message ) - exit with error code CODE, - # and message "PLUGIN CODE - $message" - nagios_exit( CRITICAL, $critical_error ) if $critical_error; - nagios_exit( WARNING, $warning_error ) if $warning_error; - nagios_exit( OK, $result ); - - # nagios_die( $message, [$CODE] ) - just like nagios_exit(), - # but CODE is optional, defaulting to UNKNOWN - do_something() - or nagios_die("do_something() failed horribly"); - do_something_critical() - or nagios_die("do_something_critical() failed", CRITICAL); - - # check_messages - check a set of message arrays, returning a - # CODE and/or a result message - $code = check_messages(critical => \@crit, warning => \@warn); - ($code, $message) = check_messages( - critical => \@crit, warning => \@warn, - ok => \@ok ); - - # get_shortname - return the default short name for this plugin - # (as used by nagios_exit/die; not exported by default) - $shortname = get_shortname(); - - -=head1 DESCRIPTION - -This module is part of the Nagios::Plugin family, a set of modules -for simplifying the creation of Nagios plugins. This module exports -convenience functions for the class methods provided by -Nagios::Plugin. It is intended for those who prefer a simpler -functional interface, and who do not need the additional -functionality of Nagios::Plugin. - -=head2 EXPORTS - -Nagios status code constants are exported by default: - - OK - WARNING - CRITICAL - UNKNOWN - DEPENDENT - -as are the following functions: - - nagios_exit - nagios_die - check_messages - -The following variables and functions are exported only on request: - - %ERRORS - %STATUS_TEXT - get_shortname - max_state - max_state_alt - - -=head2 FUNCTIONS - -The following functions are supported: - -=over 4 - -=item nagios_exit( , $message ) - -Exit with return code CODE, and a standard nagios message of the -form "PLUGIN CODE - $message". - -=item nagios_die( $message, [CODE] ) - -Same as nagios_exit(), except that CODE is optional, defaulting -to UNKNOWN. NOTE: exceptions are not raised by default to calling code. -Set C<$_use_die> flag if this functionality is required (see test code). - -=item check_messages( critical => \@crit, warning => \@warn ) - -Convenience function to check a set of message arrays and return -an appropriate nagios return code and/or a result message. Returns -only a return code in scalar context; returns a return code and an -error message in list context i.e. - - # Scalar context - $code = check_messages(critical => \@crit, warning => \@warn); - # List context - ($code, $msg) = check_messages(critical => \@crit, warning => \@warn); - -check_messages() accepts the following named arguments: - -=over 4 - -=item critical => ARRAYREF - -An arrayref of critical error messages - check_messages() returns -CRITICAL if this arrayref is non-empty. Mandatory. - -=item warning => ARRAYREF - -An arrayref of warning error messages - check_messages() returns -WARNING if this arrayref is non-empty ('critical' is checked -first). Mandatory. - -=item ok => ARRAYREF | SCALAR - -An arrayref of informational messages (or a single scalar message), -used in list context if both the 'critical' and 'warning' arrayrefs -are empty. Optional. - -=item join => SCALAR - -A string used to join the relevant array to generate the message -string returned in list context i.e. if the 'critical' array @crit -is non-empty, check_messages would return: - - join( $join, @crit ) - -as the result message. Optional; default: ' ' (space). - -=item join_all => SCALAR - -By default, only one set of messages are joined and returned in the -result message i.e. if the result is CRITICAL, only the 'critical' -messages are included in the result; if WARNING, only the 'warning' -messages are included; if OK, the 'ok' messages are included (if -supplied) i.e. the default is to return an 'errors-only' type -message. - -If join_all is supplied, however, it will be used as a string to -join the resultant critical, warning, and ok messages together i.e. -all messages are joined and returned. - -=back - -=item get_shortname - -Return the default shortname used for this plugin i.e. the first -token reported by nagios_exit/nagios_die. The default is basically - - uc basename( $ENV{NAGIOS_PLUGIN} || $0 ) - -with any leading 'CHECK_' and trailing file suffixes removed. - -get_shortname is not exported by default, so must be explicitly -imported. - -=item max_state(@a) - -Returns the worst state in the array. Order is: CRITICAL, WARNING, OK, UNKNOWN, -DEPENDENT - -The typical usage of max_state is to initialise the state as UNKNOWN and use -it on the result of various test. If no test were performed successfully the -state will still be UNKNOWN. - -=item max_state_alt(@a) - -Returns the worst state in the array. Order is: CRITICAL, WARNING, UNKNOWN, -DEPENDENT, OK - -This is a true definition of a max state (OK last) and should be used if the -internal tests performed can return UNKNOWN. - -=back - -=head1 SEE ALSO - -Nagios::Plugin; the nagios plugin developer guidelines at -http://nagiosplug.sourceforge.net/developer-guidelines.html. - - -=head1 AUTHORS - -This code is maintained by the Nagios Plugin Development Team: http://nagiosplug.sourceforge.net - - -=head1 COPYRIGHT AND LICENSE - -Copyright (C) 2006 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 diff --git a/lib/Nagios/Plugin/Getopt.pm b/lib/Nagios/Plugin/Getopt.pm deleted file mode 100644 index 22ff642..0000000 --- a/lib/Nagios/Plugin/Getopt.pm +++ /dev/null @@ -1,873 +0,0 @@ -# -# Nagios::Plugin::Getopt - OO perl module providing standardised argument -# processing for nagios plugins -# - -package Nagios::Plugin::Getopt; - -use strict; -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 Nagios::Plugin::Functions; -use Nagios::Plugin::Config; -use vars qw($VERSION); -$VERSION = $Nagios::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 http://nagiosplugins.org/extra-opts\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"; - Nagios::Plugin::Functions::_nagios_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 (@short, @long); - for (split /\|/, $opts) { - if (length $_ == 1) { - push @short, "-$_"; - } else { - push @long, "--$_"; - } - } - - my $help = join(', ', @short, @long); - if ($type) { - if ($label) { - $help .= '=' . $label; - } - else { - $help .= $type eq 'i' ? '=INTEGER' : '=STRING'; - } - } - 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, so escape everything else - $help_string =~ s/%(?!s)/%%/g; - push @options, sprintf($help_string, $default, $default, $default, $default); - } else { - push @options, $help_string; - } - } - - return ' ' . join("\n ", @options); -} - -# Output for plugin -? (or missing/invalid args) -sub _usage -{ - my $self = shift; - sprintf $self->_attr('usage'), $self->{_attr}->{plugin}; -} - -# 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 = Nagios::Plugin::Config->read($file); }; - $self->_die($@) if ($@); #TODO: add test? - - # 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->np_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; - - # Named args - if ($_[0] =~ m/^(spec|help|required|default)$/ && scalar(@_) % 2 == 0) { - %args = validate( @_, { - spec => 1, - help => 1, - default => 0, - required => 0, - label => 0, - }); - } - - # Positional args - else { - my @args = validate_pos(@_, 1, 1, 0, 0, 0); - %args = ( - spec => $args[0], - help => $args[1], - default => $args[2], - required => $args[3], - label => $args[4], - ); - } - - # 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_//; - $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{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 - -Nagios::Plugin::Getopt - OO perl module providing standardised argument -processing for Nagios plugins - - -=head1 SYNOPSIS - - use Nagios::Plugin::Getopt; - - # Instantiate object (usage is mandatory) - $ng = Nagios::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->warning; - print $ng->get('critical'); - - - -=head1 DESCRIPTION - -Nagios::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 = Nagios::Plugin::Getopt->new( - usage => 'Usage: %s --hello', - version => '0.01', - ); - -The Nagios::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