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

Annotation of nagios/check_openbgpd/check_openbgpd, Revision 1.1

1.1     ! andrew      1: #!/usr/bin/perl -T
        !             2: # $RedRiver$
        !             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:
        !            15: my $NAGIOS_OUTPUT = 0;
        !            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;
        !            63: my $state = 'OK';
        !            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
        !            96:     open my $fh , '-|', $BGPCTL, 'show', 'summary'
        !            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' ) {
        !           240:                 print_revision( $PROGNAME, '$Revision: 1.10 $ ' );
        !           241:                 exit $ERRORS{'OK'}
        !           242:             }
        !           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 ) {
        !           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";
        !           262: $PROGNAME - monitors sysctl hw.bgpstatus on OpenBSD
        !           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:
        !           283:
        !           284: $PROGNAME -w 10000:300000 -c 1000:500000 -n eBGP1 eBGP2 -n eBGP3
        !           285:
        !           286: Checks that peers eBGP1, eBGP2 and eBGP2 are within the ranges specified
        !           287:
        !           288: $PROGNAME -c 1:1 -n eBGP1 -w 200000:300000 -c 100: -n iBGP1
        !           289:
        !           290: Checks that 1 and only 1 prefix is received from from eBGP1, warns if less
        !           291: than 200000 or more than 300000 prefixes are recieved from peer iBGP1 and is
        !           292: critical if less than 100 prefixes are recieved from peer iBGP1
        !           293:
        !           294: $PROGNAME -c Idle -n iBGP1 -w
        !           295:
        !           296: EOL
        !           297:
        !           298:     print_revision( $PROGNAME, '$Revision: 1.40 $' );
        !           299:
        !           300:     print $LICENSE;
        !           301:
        !           302:     return;
        !           303: }
        !           304:
        !           305: sub print_revision {
        !           306:     my ( $prog, $rev ) = @_;
        !           307:     $rev =~ s/^\D+([\d\.]+)\D+$/v$1/xms;
        !           308:
        !           309:     say $prog, q{ }, $rev;
        !           310:
        !           311:     return;
        !           312: }
        !           313:

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