[Nagiosplug-devel] Re: check_* -w and -c switches

Paul L. Allen pla at softflare.com
Mon Mar 8 10:03:14 CET 2004


Elsewhere, Karl DeBisschop writes: 

> On Fri, 05 Mar 2004 13:05:56 +0000
> "Paul L. Allen" <pla at softflare.com> wrote:

>> I have a perl subroutine that does the same thing which you can have
>> if you want it (let me know where to send it if you do). 
> 
> Post to the list or drop into patches against utils.pm on sourceforge
> (preferred)

I couldn't see any obvious place to drop into the patches which didn't
require me to get a sourceforge login, so it's attached below.  Also
attached is the same subroutine plus a test harness that calls it to
check it copes with all the syntax permutations correctly (80 tests). 

Note that I arbitrarily decided that it would treat ~:~ as an invalid
range specifier even though theoretically it is valid (but not useful)
in order not to complicate the code any further.  I didn't see any point
in special-casing an instance that is of no practical use to anyone. 

-- 
Paul Allen
Softflare Support 

-------------- next part --------------
sub check_range ($$@)
{
  # Takes three parameters.  The first is a metric.  The second is
  # a range using Nagios plugin range syntax.  The third is an optional
  # name for the range (such as 'warning' or 'critical') which is used
  # if a usage error is generated because of an invalid range.  No
  # explicit checking is done that the metric or the range consists
  # of non-numeric values - they will be treated as zero.
    
  # Accepts ranges of the following form:
  #
  #   min:max (between min and max inclusive)
  #   min: (equivalent to min:infinity)
  #   :max (equivalent to 0:max)
  #   max (equivalent :max which is equivalent to 0:max)
  #   0 (equivalent to 0:infinity)
  #
  # The symbol ~ may be specified as the minimum portion of a range
  # to represent -infinity.  The range may be prefixed by @ to negate
  # the result (so the metric is critical if within the range).
  # Note that ~:~ is treated as an invalid range
    
  my($metric) = shift(@_);
  my($range) = shift(@_);
    
  # Take third and any subsequent parameters and concatenate with spaces
  # to form the name of the range for use in error messages.
  my($range_name) = join(' ', @_);
  $range_name = " for $range_name." if ($range_name);

  # Use strict doesn't let us do string/numeric conversions, so turn
  # off warnings to get around that problem and the problem of undefined
  # variables from the regex below.
  local($^W) = 0;
    
  my($range_ok) = 0;

  # Split the range into the optional 'invert range' prefix (@), minimum
  # bound and upper bound, allowing all the variations.
  my($invert_range, $lower, $upper) = $range =~ /^(\@)?(?:([^:])*:)?(.*)?$/;

  # The above regex has problems with 0 (which means 0:infinity), so
  # we have to correct for that (but not for :0, which means 0:0 and is
  # handled correctly by the regex).
  ($lower, $upper) = ($upper, $lower) if
    (($upper eq '0' and not $lower) and $range !~ /:/);

  # Check that upper >= lower, including the case when lower or upper is
  # ~ (negative infinity).  Set $! and die rather than just exit so we
  # can trap this in a test harness.
  if ($upper eq '~' or ($lower ne '~' and $upper ne '' and $lower > $upper ))
  {
    print "Error: range is $lower:$upper$range_name\n";
    print_usage();
    $! = $ERRORS{UNKNOWN};
    die "\n";
  }

  # If the lower bound is not ~ (negative infinity) then check that the
  # metric is greater than or equal to the lower bound.  If the lower bound
  # is ~ then the metric has to be OK because any metric has to be higher
  # than negative infinity.
  if ($lower ne '~')
  {
    $range_ok++ if ($metric >= $lower + 0);
  }
  else
  {
    $range_ok++;
  }

  $range_ok = 0 if ($upper ne '' and $metric > $upper + 0);
  $range_ok ^= 1 if ($invert_range);
    
  return($range_ok);
}
-------------- next part --------------
#! /usr/bin/perl -wT

use strict;
use lib "/usr/local/nagios/libexec" ;
use utils qw($TIMEOUT %ERRORS &print_revision &support);
use vars qw(@tests $test $result $num_tests $num_successes);

@tests =
(
  # Format: [metric, range, name, expected result]
  # 
  # 'Expected result' is the result expected from check_range: 0 if
  # check_range should return 0 (metric is outside of range), 1 if
  # check_range should return 1 (metric is inside range).  The expected
  # result can also be -1, indicating that check_range should exit with
  # plugin error code of 'UNKNOWN' after a usage error (caused by an
  # invalid range).

  # Check min:max ranges
  [-1, '2:4', 'Test 1', 0],
  [0, '2:4', 'Test 2', 0],
  [1, '2:4', 'Test 3', 0],
  [2, '2:4', 'Test 4', 1],
  [3, '2:4', 'Test 5', 1],
  [4, '2:4', 'Test 6', 1],
  [5, '2:4', 'Test 7', 0],
 
  # Check max ranges
  [-1, 2, 'Test 8', 0],
  [0, 2, 'Test 9', 1],
  [1, 2, 'Test 10', 1],
  [2, 2, 'Test 11', 1],
  [3, 2, 'Test 12', 0],
 
  # Check :max ranges
  [-1, ':2', 'Test 13', 0],
  [0, ':2', 'Test 14', 1],
  [1, ':2', 'Test 15', 1],
  [2, ':2', 'Test 16', 1],
  [3, ':2', 'Test 17', 0],
  [-1, '1:', 'Test 18', 0],
 
  # Check min: ranges
  [0, '1:', 'Test 19', 0],
  [1, '1:', 'Test 20', 1],
  [2, '1:', 'Test 21', 1],
 
  # Check 0
  [-1, 0, 'Test 22', 0],
  [0, 0, 'Test 23', 1],
  [1, 0, 'Test 24', 1],
 
  # Check ~:max ranges
  [-1, '~:1', 'Test 25', 1],
  [0, '~:1', 'Test 26', 1],
  [1, '~:1', 'Test 27', 1],
  [2, '~:1', 'Test 28', 0],
 
  # Check min:max ranges where min and max are the same, including :0
  # which should be equivalent to 0:0.
  [-1, '1:1', 'Test 29', 0],
  [0, '1:1', 'Test 30', 0],
  [1, '1:1', 'Test 31', 1],
  [2, '1:1', 'Test 32', 0],
  [-1, '0:0', 'Test 33', 0],
  [0, '0:0', 'Test 34', 1],
  [1, '0:0', 'Test 35', 0],
  [-1, ':0', 'Test 36', 0],
  [0, ':0', 'Test 37', 1],
  [1, ':0', 'Test 38', 0],
 
  # Check min:max ranges which are invalid
  [1, '4:2', 'Test 39', -1],
  [1, '~:~', 'Test 40', -1],

  # Check @min:max ranges
  [-1, '@2:4', 'Test 1', 1],
  [0, '@2:4', 'Test 2', 1],
  [1, '@2:4', 'Test 3', 1],
  [2, '@2:4', 'Test 4', 0],
  [3, '@2:4', 'Test 5', 0],
  [4, '@2:4', 'Test 6', 0],
  [5, '@2:4', 'Test 7', 1],
 
  # Check @max ranges
  [-1, '@2', 'Test 8', 1],
  [0, '@2', 'Test 9', 0],
  [1, '@2', 'Test 10', 0],
  [2, '@2', 'Test 11', 0],
  [3, '@2', 'Test 12', 1],
 
  # Check @:max ranges
  [-1, '@:2', 'Test 13', 1],
  [0, '@:2', 'Test 14', 0],
  [1, '@:2', 'Test 15', 0],
  [2, '@:2', 'Test 16', 0],
  [3, '@:2', 'Test 17', 1],
  [-1, '@1:', 'Test 18', 1],
 
  # Check @min: ranges
  [0, '@1:', 'Test 19', 1],
  [1, '@1:', 'Test 20', 0],
  [2, '@1:', 'Test 21', 0],
 
  # Check @0
  [-1, '@0', 'Test 22', 1],
  [0, '@0', 'Test 23', 0],
  [1, '@0', 'Test 24', 0],
 
  # Check @~:max ranges
  [-1, '@~:1', 'Test 25', 0],
  [0, '@~:1', 'Test 26', 0],
  [1, '@~:1', 'Test 27', 0],
  [2, '@~:1', 'Test 28', 1],
 
  # Check @min:max ranges where min and max are the same, including @:0
  # which should be equivalent to @0:0.
  [-1, '@1:1', 'Test 29', 1],
  [0, '@1:1', 'Test 30', 1],
  [1, '@1:1', 'Test 31', 0],
  [2, '@1:1', 'Test 32', 1],
  [-1, '@0:0', 'Test 33', 1],
  [0, '@0:0', 'Test 34', 0],
  [1, '@0:0', 'Test 35', 1],
  [-1, '@:0', 'Test 36', 1],
  [0, '@:0', 'Test 37', 0],
  [1, '@:0', 'Test 38', 1],
 
  # Check @min:max ranges which are invalid
  [1, '@4:2', 'Test 39', -1],
  [1, '@~:~', 'Test 40', -1],
);

foreach $test (@tests)
{
  $num_tests++;
    
  eval
  {
    $result = &check_range($test->[0], $test->[1], $test->[2]);
  };
  $result = -1 if ($@);
    
  print "$test->[2]: metric is $test->[0], range is $test->[1], ";
  if ($result == 1)
  {
    print "result is 'pass', ";
  }
  elsif ($result == -1)
  {
    print "result is 'unknown', ";
  }
  else
  {
    print "result is 'fail', ";
  }
  if ($result == $test->[3])
  {
    $num_successes++;
    print "OK\n";
  }
  else
  {
    print "Fail\n";
  }
}

print "$num_successes/$num_tests tests successful\n";

exit;

sub check_range ($$@)
{
  # Takes three parameters.  The first is a metric.  The second is
  # a range using Nagios plugin range syntax.  The third is an optional
  # name for the range (such as 'warning' or 'critical') which is used
  # if a usage error is generated because of an invalid range.  No
  # explicit checking is done that the metric or the range consists
  # of non-numeric values - they will be treated as zero.
    
  # Accepts ranges of the following form:
  #
  #   min:max (between min and max inclusive)
  #   min: (equivalent to min:infinity)
  #   :max (equivalent to 0:max)
  #   max (equivalent :max which is equivalent to 0:max)
  #   0 (equivalent to 0:infinity)
  #
  # The symbol ~ may be specified as the minimum portion of a range
  # to represent -infinity.  The range may be prefixed by @ to negate
  # the result (so the metric is critical if within the range).
  # Note that ~:~ is treated as an invalid range
    
  my($metric) = shift(@_);
  my($range) = shift(@_);
    
  # Take third and any subsequent parameters and concatenate with spaces
  # to form the name of the range for use in error messages.
  my($range_name) = join(' ', @_);
  $range_name = " for $range_name." if ($range_name);

  # Use strict doesn't let us do string/numeric conversions, so turn
  # off warnings to get around that problem and the problem of undefined
  # variables from the regex below.
  local($^W) = 0;
    
  my($range_ok) = 0;

  # Split the range into the optional 'invert range' prefix (@), minimum
  # bound and upper bound, allowing all the variations.
  my($invert_range, $lower, $upper) = $range =~ /^(\@)?(?:([^:])*:)?(.*)?$/;

  # The above regex has problems with 0 (which means 0:infinity), so
  # we have to correct for that (but not for :0, which means 0:0 and is
  # handled correctly by the regex).
  ($lower, $upper) = ($upper, $lower) if
    (($upper eq '0' and not $lower) and $range !~ /:/);

  # Check that upper >= lower, including the case when lower or upper is
  # ~ (negative infinity).  Set $! and die rather than just exit so we
  # can trap this in a test harness.
  if ($upper eq '~' or ($lower ne '~' and $upper ne '' and $lower > $upper ))
  {
    print "Error: range is $lower:$upper$range_name\n";
    print_usage();
    $! = $ERRORS{UNKNOWN};
    die "\n";
  }

  # If the lower bound is not ~ (negative infinity) then check that the
  # metric is greater than or equal to the lower bound.  If the lower bound
  # is ~ then the metric has to be OK because any metric has to be higher
  # than negative infinity.
  if ($lower ne '~')
  {
    $range_ok++ if ($metric >= $lower + 0);
  }
  else
  {
    $range_ok++;
  }

  $range_ok = 0 if ($upper ne '' and $metric > $upper + 0);
  $range_ok ^= 1 if ($invert_range);
    
  return($range_ok);
}


sub print_usage
{
   # Dummy print_usage subroutine to so the test harness doesn't complain
   # when we specify a range with an lower bound greater than the upper bound.
}



More information about the Devel mailing list