version 1.1, 2009/11/13 02:05:20 |
version 1.11, 2024/06/09 23:34:58 |
|
|
#!/usr/bin/perl -T |
#!/usr/bin/perl -T |
# $RedRiver$ |
# $AFresh1: check_openbgpd,v 1.10 2015/03/26 03:44:15 andrew Exp $ |
######################################################################## |
######################################################################## |
# check_openbgpd *** A nagios check for OpenBSD bgpd |
# check_openbgpd *** A nagios check for OpenBSD bgpd |
# |
# |
|
|
use warnings; |
use warnings; |
|
|
use 5.010; |
use 5.010; |
|
use if $] >= 5.016, experimental => 'switch'; |
|
|
local %ENV = (); |
local %ENV = (); |
|
|
my $NAGIOS_OUTPUT = 0; |
my $NAGIOS_OUTPUT = 1; |
|
|
my $LICENSE = <<'EOL'; |
my $LICENSE = <<'EOL'; |
Copyright (c) 2009 Andrew Fresh <andrew@afresh1.com> |
Copyright (c) 2009-2015 Andrew Fresh <andrew@afresh1.com> |
Permission to use, copy, modify, and distribute this software for any |
Permission to use, copy, modify, and distribute this software for any |
purpose with or without fee is hereby granted, provided that the above |
purpose with or without fee is hereby granted, provided that the above |
copyright notice and this permission notice appear in all copies. |
copyright notice and this permission notice appear in all copies. |
|
|
exit $ERRORS{'OK'}; |
exit $ERRORS{'OK'}; |
} |
} |
|
|
my @STATUS = read_status(); |
my @STATUS = read_status( $CHECKS{_SOCKET} ); |
my %STATES = check_status( \@STATUS, \%CHECKS ); |
my %STATES = check_status( \@STATUS, \%CHECKS ); |
|
|
my $have_results = 0; |
my $have_results = 0; |
my $state = 'OK'; |
my $state = 'OK'; |
foreach |
foreach |
my $error ( reverse sort { $ERRORS{$a} <=> $ERRORS{$b} } keys %ERRORS ) |
my $error ( reverse sort { $ERRORS{$a} <=> $ERRORS{$b} } keys %ERRORS ) |
{ |
{ |
|
|
exit $ERRORS{$state}; |
exit $ERRORS{$state}; |
|
|
sub read_status { |
sub read_status { |
my ($status) = @_; |
my ($socket) = @_; |
my @S; |
my @S; |
|
|
|
my @cmd = ($BGPCTL); |
|
if ($socket) { |
|
push @cmd, '-s', $socket; |
|
} |
|
push @cmd, 'show', 'summary'; |
|
|
#open my $fh, '<', 'output' # XXX |
#open my $fh, '<', 'output' # XXX |
open my $fh , '-|', $BGPCTL, 'show', 'summary' |
open my $fh, '-|', @cmd or die "Couldn't open bgpctl: $!\n"; |
or die "Couldn't open bgpctl: $!\n"; |
|
while (<$fh>) { |
while (<$fh>) { |
chomp; |
chomp; |
push @S, parse_line($_); |
push @S, parse_line($_); |
|
|
sub parse_check { |
sub parse_check { |
my $check = shift; |
my $check = shift; |
|
|
return { match => [] } unless $check; |
unless ($check) { |
|
print_help(); |
|
exit $ERRORS{'OK'} |
|
} |
|
|
my @values = split /,\s*/xms, $check; |
my @values = split /,\s*/xms, $check; |
|
|
my %c = ( match => [] ); |
my %c = ( match => [] ); |
|
|
|
|
foreach my $d ( 'low', 'high' ) { |
foreach my $d ( 'low', 'high' ) { |
if ( defined $c{$d} ) { |
if ( defined $c{$d} ) { |
$c{$d} =~ s/[^-\d\.]//gxms; |
$c{$d} =~ s/[^-\d\.\%]//gxms; |
if ( !length $c{$d} ) { |
if ( !length $c{$d} ) { |
delete $c{$d}; |
delete $c{$d}; |
} |
} |
|
|
my ( $S, $C ) = @_; |
my ( $S, $C ) = @_; |
|
|
my %states; |
my %states; |
my %neighbors; |
my %neighbors = map { $_ => $C->{$_} } qw( _SOCKET _UNKNOWN ); |
STATE: foreach my $s ( @{$S} ) { |
STATE: foreach my $s ( @{$S} ) { |
my $n = $s->{neighbor}; |
my $n = $s->{neighbor}; |
$neighbors{$n} = $s; |
$neighbors{$n} = $s; |
|
|
my $result; |
my $result; |
|
|
if ( my $c = $C->{$n} ) { |
if ( my $c = $C->{$n} || $C->{_UNKNOWN} ) { |
CODE: foreach my $code ( 'CRITICAL', 'WARNING' ) { |
CODE: foreach my $code ( 'CRITICAL', 'WARNING' ) { |
next CODE if ( ref $c->{$code} ne 'HASH' ); |
next CODE if ( ref $c->{$code} ne 'HASH' ); |
my $data = $s->{state}; |
my $data = $s->{state}; |
|
|
|
|
if ( $c->{low} || $c->{high} ) { |
if ( $c->{low} || $c->{high} ) { |
$result = undef; |
$result = undef; |
my $num = $d; |
my ( $num, $max ) = split m{/}xms, $d; |
$num =~ s/[^-\d\.]//gxms; |
$num =~ s/[^-\d\.]//gxms; |
|
|
if ( !length $num ) { |
if ( !length $num ) { |
return 'State (' . $d . ') is not numeric'; |
return 'State (' . $d . ') is not numeric'; |
} |
} |
|
|
if ( $c->{low} && $num < $c->{low} ) { |
DIRECTION: foreach my $dir (qw( low high )) { |
return 'is below threshold (' . $d . ' < ' . $c->{low} . ')'; |
if ( !$c->{$dir} ) { next DIRECTION; } |
} |
|
|
|
if ( $c->{high} && $num > $c->{high} ) { |
my $check = $c->{$dir}; |
return 'is above threshold (' . $d . ' > ' . $c->{high} . ')'; |
my $cnum = $num; |
|
|
|
if ( $check =~ s/\%$//xms ) { |
|
if ( !defined $max ) { |
|
return 'max-prefix not specified and % check requested'; |
|
} |
|
|
|
# convert to percent |
|
$cnum = 100 * $cnum / $max; |
|
} |
|
|
|
my @nums = ( $cnum, $check ); |
|
my $abovebelow = 'below'; |
|
my $symbol = '<'; |
|
if ( $dir eq 'high' ) { |
|
@nums = ( $check, $cnum ); |
|
$abovebelow = 'above'; |
|
$symbol = '>'; |
|
} |
|
|
|
if ( $nums[0] < $nums[1] ) { |
|
return join q{ }, 'is', $abovebelow, |
|
'threshold (' . $d, |
|
$symbol, $c->{$dir} . ')'; |
|
} |
} |
} |
} |
} |
|
|
|
|
state( $w, $c ); |
state( $w, $c ); |
|
|
my $opt = shift @argv; |
my $opt = shift @argv; |
given ($opt) { |
for ($opt) { |
when ( '-V' || '--version' ) { |
if ( $_ eq '-V' || $_ eq '--version' ) { |
print_revision( $PROGNAME, '$Revision$ ' ); |
print_revision( $PROGNAME, '$Revision$ ' ); |
exit $ERRORS{'OK'} |
exit $ERRORS{'OK'} |
} |
} |
when ( /^-?-h(?:elp)?/xms ) { print_help(); exit $ERRORS{'OK'} } |
elsif (/^-?-h(?:elp)?\Z/xms) { print_help(); exit $ERRORS{'OK'} } |
when ( /^-?-w(?:arning)?/xms ) { $w = parse_check( shift @argv ) } |
elsif (/^-?-s(?:ocket)?\Z/xms) { |
when ( /^-?-c(?:ritical)?/xms ) { $c = parse_check( shift @argv ) } |
$checks{_SOCKET} = shift @argv |
when ( /^-?-n(?:eighbor)?/xms ) { |
|| do { print_help(); exit $ERRORS{'OK'} } |
|
} |
|
elsif (/^-?-w(?:arning)?\Z/xms) { $w = parse_check( shift @argv ) } |
|
elsif (/^-?-c(?:ritical)?\Z/xms) { $c = parse_check( shift @argv ) } |
|
elsif (/^-?-u(?:nknown)?\Z/xms) { |
|
$checks{_UNKNOWN} = { |
|
WARNING => $w, |
|
CRITICAL => $c, |
|
}; |
|
} |
|
elsif (/^-?-n(?:eighbor)?\Z/xms) { |
while ( @argv && $argv[0] !~ /^-/xms ) { |
while ( @argv && $argv[0] !~ /^-/xms ) { |
$checks{ shift @argv } = { |
$checks{ shift @argv } = { |
WARNING => $w, |
WARNING => $w, |
CRITICAL => $c |
CRITICAL => $c, |
} |
}; |
} |
} |
} |
} |
default { print_help(); exit $ERRORS{'UNKNOWN'} } |
else { print_help(); exit $ERRORS{'UNKNOWN'} } |
} |
} |
} |
} |
return %checks; |
return %checks; |
|
|
|
|
sub print_help { |
sub print_help { |
print <<"EOL"; |
print <<"EOL"; |
$PROGNAME - monitors sysctl hw.bgpstatus on OpenBSD |
$PROGNAME - checks status of OpenBGPd peers |
$PROGNAME [ -w ENTRY ][ -c ENTRY ][ -n NEIGHBOR [ NEIGHBOR2 ] ] |
$PROGNAME [ -s SOCKET ][ -w ENTRY ][ -c ENTRY ]( -u | -n NEIGHBOR ) |
|
|
Usage: |
Usage: |
|
-s, --socket SOCKET |
|
Path to bgpd socket to use. See -r in bgpd(8). |
-w, --warning RANGE or single ENTRY |
-w, --warning RANGE or single ENTRY |
Exit with WARNING status if outside of RANGE or if != ENTRY |
Exit with WARNING status if outside of RANGE or if != ENTRY |
|
May be entered multiple times. |
-c, --critical RANGE or single ENTRY |
-c, --critical RANGE or single ENTRY |
Exit with CRITICAL status if outside of RANGE or if != ENTRY |
Exit with CRITICAL status if outside of RANGE or if != ENTRY |
|
May be entered multiple times. |
-n, --neighbor NEIGHBOR |
-n, --neighbor NEIGHBOR |
The name of the Neighbor |
The name of the Neighbor, can be a space separated list of neighbors. |
|
May be entered multiple times. |
|
-u, --unknown |
|
As if you specified -n for all unknown neighbors |
|
|
ENTRY is a comma separated list of items to match against. Each item can be |
ENTRY is a comma separated list of items to match against. Each item can be |
a RANGE or it will just be matched against the status. |
a RANGE or it will just be matched against the status. |
|
|
RANGE is specified as two optional numbers separated with a colon (:). The |
RANGE is specified as two optional numbers separated with a colon (:). The |
check is that the value is between the two numbers. If either number is left |
check is that the value is between the two numbers. If either number is left |
off, that check is ignored |
off, that check is ignored. |
|
|
|
If either number in a RANGE is specified as a percent, check is that |
|
max-prefix is specified and that the number is within the specified percent. |
|
|
NEIGHBOR is the name that shows when running "bgpctl show summary" |
NEIGHBOR is the name that shows when running "bgpctl show summary" |
|
|
Examples: |
Examples: |
|
(where many of the numbers would probably have to be multiplied by 1000) |
|
|
$PROGNAME -w 10000:300000 -c 1000:500000 -n eBGP1 eBGP2 -n eBGP3 |
Any time a NEIGHBOR is specified on the command line but does NOT show up in |
|
the output causes a CRITICAL result. |
|
|
Checks that peers eBGP1, eBGP2 and eBGP2 are within the ranges specified |
Any time a NEIGHBOR that is NOT specified on the command line shows up in the |
|
output causes a CRITICAL result. If -u is specified, it treats NEIGHBOR as if |
|
it were specified at that position. |
|
|
$PROGNAME -c 1:1 -n eBGP1 -w 200000:300000 -c 100: -n iBGP1 |
|
|
|
Checks that 1 and only 1 prefix is received from from eBGP1, warns if less |
$PROGNAME -c Idle -n P1 -c 1:1 -n P2 -w 200:300 -c Active,10: -n P3 |
than 200000 or more than 300000 prefixes are recieved from peer iBGP1 and is |
|
critical if less than 100 prefixes are recieved from peer iBGP1 |
|
|
|
$PROGNAME -c Idle -n iBGP1 -w |
CRITICAL |
|
If P1 is any value but Idle. |
|
If P2 is any value but 1. |
|
If P3 is below 10 or any non-numeric value other than "Active". |
|
|
|
WARNING |
|
If P3 is above 10 and below 200 or above 300. |
|
|
|
|
|
$PROGNAME -u -w 50%:70% -c 10%:90% -n P2 P3 |
|
|
|
No checks of unknown neighbors. |
|
|
|
CRITICAL |
|
If P2 or P3 do not have max-prefix set or if they do but learned prefixes |
|
are below 10% or above 90% of max-prefix or any non-numeric value. |
|
|
|
WARNING |
|
If P2 or P3 have learned prefixes below 50% or above 70% of max-prefix. |
|
|
|
|
|
$PROGNAME -w 50%:70% -c 10%:90% -u |
|
|
|
CRITICAL |
|
If any neighbor does not have max-prefix set or if they do but learned |
|
prefixes are below 10% or above 90% of max-prefix or any non-numeric value. |
|
|
|
WARNING |
|
If any neighbor have learned prefixes below 50% or above 70% of max-prefix. |
|
|
EOL |
EOL |
|
|