[BACK]Return to check_openbgpd CVS log [TXT][DIR] Up to [local] / nagios / check_openbgpd

Annotation of nagios/check_openbgpd/check_openbgpd, Revision 1.2

1.1       andrew      1: #!/usr/bin/perl -T
1.2     ! andrew      2: # $RedRiver: check_openbgpd,v 1.1 2009/11/13 02:05:20 andrew Exp $
1.1       andrew      3: ########################################################################
                      4: # check_openbgpd *** A nagios check for OpenBSD bgpd
                      5: #
                      6: # 2009.11.12 #*#*# andrew fresh <andrew@afresh1.com>
                      7: ########################################################################
                      8: use strict;
                      9: use warnings;
                     10:
                     11: use 5.010;
                     12:
                     13: local %ENV = ();
                     14:
1.2     ! andrew     15: my $NAGIOS_OUTPUT = 1;
1.1       andrew     16:
                     17: my $LICENSE = <<'EOL';
                     18: Copyright (c) 2009 Andrew Fresh <andrew@afresh1.com>
                     19: Permission to use, copy, modify, and distribute this software for any
                     20: purpose with or without fee is hereby granted, provided that the above
                     21: copyright notice and this permission notice appear in all copies.
                     22:
                     23: THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     24: WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     25: MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     26: ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     27: WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     28: ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     29: OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     30: EOL
                     31:
                     32: my $PROGNAME = 'check_openbgpd';
                     33: my $BGPCTL   = '/usr/sbin/bgpctl';
                     34:
                     35: use POSIX;
                     36: use Config;
                     37: my $PREFIX;
                     38:
                     39: BEGIN {
                     40:     ## no critic 'warnings'
                     41:     no warnings 'uninitialized';
                     42:     $PREFIX = "${PREFIX}" || '/usr/local';    # Magic for OpenBSD ports tree
                     43: }
                     44: use lib $PREFIX . '/libexec/nagios';
                     45: use utils qw($TIMEOUT %ERRORS &support);
                     46:
                     47: $SIG{'ALRM'} = sub {
                     48:     print("ERROR: $PROGNAME timeout\n");
                     49:     exit $ERRORS{'UNKNOWN'};
                     50: };
                     51: alarm($TIMEOUT);
                     52:
                     53: my %CHECKS = getopt(@ARGV);
                     54: if ( !%CHECKS ) {
                     55:     print_help();
                     56:     exit $ERRORS{'OK'};
                     57: }
                     58:
                     59: my @STATUS = read_status();
                     60: my %STATES = check_status( \@STATUS, \%CHECKS );
                     61:
                     62: my $have_results = 0;
1.2     ! andrew     63: my $state        = 'OK';
1.1       andrew     64: foreach
                     65:     my $error ( reverse sort { $ERRORS{$a} <=> $ERRORS{$b} } keys %ERRORS )
                     66: {
                     67:     if ( exists $STATES{$error} ) {
                     68:         $have_results++;
                     69:         $state = $error if $ERRORS{$state} < $ERRORS{$error};
                     70:
                     71:         if ($NAGIOS_OUTPUT) {
                     72:             print $error . ' (' . scalar( @{ $STATES{$error} } ) . ')';
                     73:             if ( $error ne 'OK' ) {
                     74:                 print '<br>';
                     75:                 print map {" - $_<br>"} @{ $STATES{$error} };
                     76:             }
                     77:         }
                     78:         else {
                     79:             print $error . ' (' . scalar( @{ $STATES{$error} } ) . "):\n";
                     80:             foreach ( @{ $STATES{$error} } ) {
                     81:                 print "   $_\n";
                     82:             }
                     83:         }
                     84:     }
                     85: }
                     86: if ( $have_results == 0 ) {
                     87:     print "No results found\n";
                     88: }
                     89: exit $ERRORS{$state};
                     90:
                     91: sub read_status {
                     92:     my ($status) = @_;
                     93:     my @S;
                     94:
                     95:     #open my $fh, '<', 'output'    # XXX
1.2     ! andrew     96:     open my $fh, '-|', $BGPCTL, 'show', 'summary'
1.1       andrew     97:         or die "Couldn't open bgpctl: $!\n";
                     98:     while (<$fh>) {
                     99:         chomp;
                    100:         push @S, parse_line($_);
                    101:     }
                    102:     ## no critic 'die'
                    103:     close $fh
                    104:         or die $!
                    105:         ? "Error closing sysctl pipe: $!\n"
                    106:         : "Exit status $? from sysctl\n";
                    107:
                    108:     return grep { exists $_->{neighbor} && $_->{as} ne 'AS' } @S;
                    109: }
                    110:
                    111: sub parse_line {
                    112:     my ($c) = @_;
                    113:     my ( $neighbor, $as, $rcvd, $sent, $outq, $updown, $state, )
                    114:         = $c
                    115:         =~ /^(.*?)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*$/xms;
                    116:     return {
                    117:         neighbor => $neighbor,
                    118:         as       => $as,
                    119:         rcvd     => $rcvd,
                    120:         sent     => $sent,
                    121:         outq     => $outq,
                    122:         updown   => $updown,
                    123:         state    => $state,
                    124:         line     => $c,
                    125:     };
                    126: }
                    127:
                    128: sub parse_check {
                    129:     my $check = shift;
                    130:
                    131:     return { match => [] } unless $check;
                    132:     my @values = split /,\s*/xms, $check;
                    133:
                    134:     my %c = ( match => [] );
                    135:     foreach my $v (@values) {
                    136:         if ( $v =~ /:/xms ) {
                    137:             ( $c{low}, $c{high} ) = split /:/xms, $v;
                    138:         }
                    139:         else {
                    140:             push @{ $c{match} }, $v;
                    141:         }
                    142:     }
                    143:
                    144:     foreach my $d ( 'low', 'high' ) {
                    145:         if ( defined $c{$d} ) {
                    146:             $c{$d} =~ s/[^-\d\.]//gxms;
                    147:             if ( !length $c{$d} ) {
                    148:                 delete $c{$d};
                    149:             }
                    150:         }
                    151:     }
                    152:
                    153:     return \%c;
                    154: }
                    155:
                    156: sub check_status {
                    157:     my ( $S, $C ) = @_;
                    158:
                    159:     my %states;
                    160:     my %neighbors;
                    161: STATE: foreach my $s ( @{$S} ) {
                    162:         my $n = $s->{neighbor};
                    163:         $neighbors{$n} = $s;
                    164:
                    165:         my $result;
                    166:
                    167:         if ( my $c = $C->{$n} ) {
                    168:         CODE: foreach my $code ( 'CRITICAL', 'WARNING' ) {
                    169:                 next CODE if ( ref $c->{$code} ne 'HASH' );
                    170:                 my $data = $s->{state};
                    171:
                    172:                 my $result = check_item( $data, $c->{$code} );
                    173:
                    174:                 if ($result) {
                    175:                     push @{ $states{$code} }, "[$n] $result";
                    176:                     next STATE;
                    177:                 }
                    178:             }
                    179:         }
                    180:         else {
                    181:             push @{ $states{CRITICAL} }, '[' . $n . '] Unknown Neighbor';
                    182:             next STATE;
                    183:         }
                    184:
                    185:         push @{ $states{OK} }, $n;
                    186:     }
                    187:
                    188:     foreach my $n ( keys %{$C} ) {
                    189:         if ( !exists $neighbors{$n} ) {
                    190:             push @{ $states{CRITICAL} }, '[' . $n . '] Missing Neighbor';
                    191:         }
                    192:     }
                    193:
                    194:     return %states;
                    195: }
                    196:
                    197: sub check_item {
                    198:     my ( $d, $c ) = @_;
                    199:
                    200:     my $result;
                    201:
                    202:     if ( $c->{match} && @{ $c->{match} } ) {
                    203:         foreach my $m ( @{ $c->{match} } ) {
                    204:             return if $m eq $d;
                    205:         }
                    206:         $result = 'State (' . $d . ') is outside of acceptable values';
                    207:     }
                    208:
                    209:     if ( $c->{low} || $c->{high} ) {
                    210:         $result = undef;
                    211:         my $num = $d;
                    212:         $num =~ s/[^-\d\.]//gxms;
                    213:
                    214:         if ( !length $num ) {
                    215:             return 'State (' . $d . ') is not numeric';
                    216:         }
                    217:
                    218:         if ( $c->{low} && $num < $c->{low} ) {
                    219:             return 'is below threshold (' . $d . ' < ' . $c->{low} . ')';
                    220:         }
                    221:
                    222:         if ( $c->{high} && $num > $c->{high} ) {
                    223:             return 'is above threshold (' . $d . ' > ' . $c->{high} . ')';
                    224:         }
                    225:     }
                    226:
                    227:     return $result;
                    228: }
                    229:
                    230: sub getopt {
                    231:     my (@argv) = @_;
                    232:
                    233:     my %checks;
                    234:     while (@argv) {
                    235:         state( $w, $c );
                    236:
                    237:         my $opt = shift @argv;
                    238:         given ($opt) {
                    239:             when ( '-V' || '--version' ) {
1.2     ! andrew    240:                 print_revision( $PROGNAME, '$Revision: 1.1 $ ' );
1.1       andrew    241:                 exit $ERRORS{'OK'}
                    242:             }
1.2     ! andrew    243:             when (/^-?-h(?:elp)?/xms) { print_help(); exit $ERRORS{'OK'} }
        !           244:             when (/^-?-w(?:arning)?/xms)  { $w = parse_check( shift @argv ) }
        !           245:             when (/^-?-c(?:ritical)?/xms) { $c = parse_check( shift @argv ) }
        !           246:             when (/^-?-n(?:eighbor)?/xms) {
1.1       andrew    247:                 while ( @argv && $argv[0] !~ /^-/xms ) {
                    248:                     $checks{ shift @argv } = {
                    249:                         WARNING      => $w,
                    250:                             CRITICAL => $c
                    251:                     }
                    252:                 }
                    253:             }
                    254:             default { print_help(); exit $ERRORS{'UNKNOWN'} }
                    255:         }
                    256:     }
                    257:     return %checks;
                    258: }
                    259:
                    260: sub print_help {
                    261:     print <<"EOL";
1.2     ! andrew    262: $PROGNAME - checks status of OpenBGPd peers
1.1       andrew    263:     $PROGNAME [ -w ENTRY ][ -c ENTRY ][ -n NEIGHBOR [ NEIGHBOR2 ] ]
                    264:
                    265: Usage:
                    266:     -w, --warning RANGE or single ENTRY
                    267:         Exit with WARNING status if outside of RANGE or if != ENTRY
                    268:     -c, --critical RANGE or single ENTRY
                    269:         Exit with CRITICAL status if outside of RANGE or if != ENTRY
                    270:     -n, --neighbor NEIGHBOR
                    271:         The name of the Neighbor
                    272:
                    273: ENTRY is a comma separated list of items to match against.  Each item can be
                    274: a RANGE or it will just be matched against the status.
                    275:
                    276: RANGE is specified as two optional numbers separated with a colon (:).  The
                    277: check is that the value is between the two numbers.  If either number is left
                    278: off, that check is ignored
                    279:
                    280: NEIGHBOR is the name that shows when running "bgpctl show summary"
                    281:
                    282: Examples:
1.2     ! andrew    283: (where many of the numbers would probably have to be multiplied by 1000)
1.1       andrew    284:
1.2     ! andrew    285: Any time a NEIGHBOR is specified on the command line but does NOT show up in
        !           286: the output causes a CRITICAL result.
1.1       andrew    287:
1.2     ! andrew    288: Any time a NEIGHBOR that is NOT specified on the command line shows up in the
        !           289: output causes a CRITICAL result.
1.1       andrew    290:
                    291:
1.2     ! andrew    292: $PROGNAME -w 10:300 -c 10:500 -n P1 P2 -n P3
1.1       andrew    293:
1.2     ! andrew    294: CRITICAL
        !           295:     If any of P1, P2, P3 are below 10, above 500 or any non-numeric value.
        !           296:
        !           297: WARNING
        !           298:     If any of P1, P2, P3 are above 300.
        !           299:
        !           300:
        !           301: $PROGNAME -c Idle -n P1 -c 1:1 -n P2 -w 200:300 -c Active,10: -n P3
        !           302:
        !           303: CRITICAL
        !           304:     If P1 is any value but Idle.
        !           305:     If P2 is any value but 1.
        !           306:     If P3 is below 10 or any non-numeric value other than "Active".
        !           307:
        !           308: WARNING
        !           309:     If P3 is above 10 and below 200 or above 300.
1.1       andrew    310:
                    311: EOL
                    312:
1.2     ! andrew    313:     print_revision( $PROGNAME, '$Revision: 1.1 $' );
1.1       andrew    314:
                    315:     print $LICENSE;
                    316:
                    317:     return;
                    318: }
                    319:
                    320: sub print_revision {
                    321:     my ( $prog, $rev ) = @_;
                    322:     $rev =~ s/^\D+([\d\.]+)\D+$/v$1/xms;
                    323:
                    324:     say $prog, q{ }, $rev;
                    325:
                    326:     return;
                    327: }
                    328:

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>