YATG::Store::NSCA - Back-end module to send polled data to a Nagios service


YATG documentation Contained in the YATG distribution.

Index


Code Index:

NAME

Top

YATG::Store::NSCA - Back-end module to send polled data to a Nagios service

DESCRIPTION

Top

This module checks for device ports which are administratively enabled, but which are showing not connected to anything, at the time of polling. A Nagios CRITICAL result will be generated for such ports.

Only one check result per device is submitted (i.e. not one result per port). If there are multiple ports in an alarm state on the same device, then they will all be mentioned in the single service check report.

When all enabled ports are connected, an OK result is returned.

CONFIGURATION

Top

At a minimum, you must provide details of the location of your Nagios NSCA server, in the main configuration file:

 nsca:
     nsca_server: '192.0.2.1'

In your YATG configuration file, you must also include this store module on the OIDs required to generate a check result:

 oids:
     "ifOperStatus":   [ifindex, nsca]
     "ifAlias":        [ifindex, nsca]

Optional Configuration

You can also supply the following settings in the main configuration file to override builtin defaults, like so:

 nsca:
     send_nsca_cmd: '/usr/bin/send_nsca'
     config_file:   '/etc/send_nsca.cfg'
     ignore_ports:  '^(?:Vlan|Po)\d+$'
     ignore_descr:  '(?:SPAN)'
     service_name:  'Interfaces Status'

send_nsca_cmd

The location of the send_nsca command on your system. YATG will default to searching for send_nsca in the application's current PATH.

config_file

The location of the configuration file for the send_nsca program. This defaults to /etc/send_nsca.cfg.

ignore_ports

Device port names (OID ifDescr) to skip when submitting results. This defaults to anything like a Vlan interface, or Cisco PortChannel. Supply the content of a Perl regular expression, as in the example above.

ignore_descr

Device port description fields matching this value cause the port to be skipped when submitting results. This defaults to anything containing the word "SPAN". Supply the content of a Perl regular expression, as in the example above.

service_name

The Nagios Service Check name to use when submitting results. This must match the configured name on your Nagios server, and defaults to "Interfaces Status".

SEE ALSO

Top

Opsview at http://www.opsview.org

AUTHOR

Top

Oliver Gorwits <oliver.gorwits@oucs.ox.ac.uk>

COPYRIGHT & LICENSE

Top


YATG documentation Contained in the YATG distribution.

package YATG::Store::NSCA;

use strict;
use warnings FATAL => 'all';

use YATG::SharedStorage;
YATG::SharedStorage->factory(qw(dns_cache));

use Net::DNS;
use Regexp::Common 'net';

sub store {
    my ($config, $stamp, $results) = @_;
    my $dns_cache = YATG::SharedStorage->dns_cache;
    my $ignore_ports  = $config->{nsca}->{ignore_ports};
    my $ignore_descr  = $config->{nsca}->{ignore_descr};
    my $send_nsca_cmd = &find_command($config, 'send_nsca');
    my $send_nsca_cfg = $config->{nsca}->{config_file};
    my $service_name  = $config->{nsca}->{service_name};

    my $nsca_server = $config->{nsca}->{nsca_server}
        or die "Must specify an nsca server in configuration.\n";

    # results look like this:
    #   $results->{device}->{leaf}->{port} = {value}

    my $status = {};
    # build $status->{host}->{port}->{descr => '', state => ''}
    foreach my $device (keys %$results) {
        foreach my $leaf (keys %{$results->{$device}}) {
            foreach my $port (keys %{$results->{$device}->{$leaf}}) {

                my $host = 
                    $dns_cache->{$device} || &get_hostname_for($device) || next;
                $status->{$host}->{$port}->{$leaf} = $results->{$device}->{$leaf}->{$port};
            } # port
        } # leaf
    } # device

    # get handle in outer scope
    open my $oldout, '>&', \*STDOUT or die "Can't dup STDOUT: $!";

    # back up STDOUT then redirect it to quieten send_nsca command
    unless ($ENV{YATG_DEBUG} || $config->{yatg}->{debug}) {
        open STDOUT, '>', '/dev/null'   or die "Can't redirect STDOUT: $!";
    }

    # open connection to send_nsca
    open(my $send_nsca, '|-', $send_nsca_cmd, '-H', $nsca_server, '-c', $send_nsca_cfg, '-d', '!', '-to', 1)
        or die "can't fork send_nsca: $!";

    # build and send report for each host
    foreach my $host (keys %$status) {
        my $combined_error=q{}; # combine the error messages to fit in nagios report

        foreach my $port (keys %{$status->{$host}}) {
            next if $port =~ m/$ignore_ports/;

            my $ifOperStatus = $status->{$host}->{$port}->{ifOperStatus} || next;
            my $ifAlias      = $status->{$host}->{$port}->{ifAlias}      || '';
            next if length $ifAlias and $ifAlias =~ m/$ignore_descr/;

            if ($ifOperStatus ne 'up') {
                $combined_error .= " WARN: $port ($ifAlias) is $ifOperStatus;";
            }
        } # port

        # $ECHO "$SERVER;$SERVICE;$RESULT;$OUTPUT" | $CMD -H $DEST_HOST -c $CFG -d ";"
        if (length $combined_error) {
            print $send_nsca "$host!$service_name!2!$combined_error\n";
        }
        else {
            print $send_nsca "$host!$service_name!0! OK: all activated interfaces are running\n";
        }
    } # host

    # close connection to send_nsca (will chirp)
    close $send_nsca or die "can't close send_nsca: $!";

    # restore STDOUT
    open STDOUT, '>&', $oldout or die "Can't dup \$oldout: $!";

    return 1;
}

# get hostname for ip
sub get_hostname_for {
    my $device = shift;
    return $device if $device !~ m/^$RE{net}{IPv4}$/;

    my $res   = Net::DNS::Resolver->new;
    my $query = $res->search($device);

    my $hostname = $device; 
    if ($query) {
        foreach my $rr ($query->answer) {
            next unless $rr->type eq 'PTR';
            $hostname = $rr->ptrdname;
            last;
        }
    }
    return $hostname;
}

sub find_command {
    my ($config, $command) = @_;
    my $key = $command . '_cmd';

    return $config->{nsca}->{$key} if
        exists $config->{nsca}->{$key}
        and defined $config->{nsca}->{$key};

    use Config;
    require File::Spec;
    require ExtUtils::MakeMaker;

    if( File::Spec->file_name_is_absolute($command) ) {
        return MM->maybe_command($command);
    }
    else {
        for my $dir (
            (split /\Q$Config{path_sep}\E/, $ENV{PATH}),
            File::Spec->curdir
        ) {           
            my $abs = File::Spec->catfile($dir, $command);
            return $abs if $abs = MM->maybe_command($abs);
        }
    }

    die "Could not find command [$command] in path\n";
}

1;

__END__