Remove old PERL plugins

I'm not able to support them
This commit is contained in:
Sven Velt 2016-06-02 21:05:53 +02:00
parent c3786e5ae1
commit 6b146c728f
8 changed files with 0 additions and 3592 deletions

View file

@ -1,602 +0,0 @@
#!/usr/bin/perl
#############################################################################
# (c) 2001, 2003 Juniper Networks, Inc. #
# (c) 2011-2012 Sebastian "tokkee" Harl <sh@teamix.net> #
# and team(ix) GmbH, Nuernberg, Germany #
# #
# This file is part of "team(ix) Monitoring Plugins" #
# URL: http://oss.teamix.org/projects/monitoringplugins/ #
# #
# All rights reserved. #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions #
# are met: #
# 1. Redistributions of source code must retain the above copyright #
# notice, this list of conditions and the following disclaimer. #
# 2. Redistributions in binary form must reproduce the above copyright #
# notice, this list of conditions and the following disclaimer in the #
# documentation and/or other materials provided with the distribution. #
# 3. The name of the copyright owner may not be used to endorse or #
# promote products derived from this software without specific prior #
# written permission. #
# #
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR #
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE #
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, #
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES #
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR #
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) #
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, #
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING #
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE #
# POSSIBILITY OF SUCH DAMAGE. #
#############################################################################
use strict;
use warnings;
use utf8;
use JUNOS::Device;
use JUNOS::Trace;
use FindBin qw( $Bin );
use lib "$Bin/perl/lib";
use Nagios::Plugin::JUNOS;
binmode STDOUT, ":utf8";
# TODO:
# * chassis_routing_engine: show chassis routing-engine (-> number and status)
my $plugin = Nagios::Plugin::JUNOS->new(
plugin => 'check_junos',
shortname => 'check_junos',
version => '0.1',
url => 'http://oss.teamix.org/projects/monitoringplugins',
blurb => 'Monitor Juniper™ Switches.',
usage =>
"Usage: %s [-v|--verbose] [-H <host>] [-p <port>] [-t <timeout]
[-C] [-U <user>] [-P <password] check-tuple [...]",
license =>
"This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY.
It may be used, redistributed and/or modified under the terms of the 3-Clause
BSD License (see http://opensource.org/licenses/BSD-3-Clause).",
extra => "
This plugin connects to a Juniper Switch device and checks various of its
components.
A check-tuple consists of the name of the check and, optionally, a \"target\"
which more closely specifies which characteristics should be checked, and
warning and critical thresholds:
checkname[,target[,warning[,critical]]]
The following checks are available:
* interfaces: Status of interfaces. If a target is specified, only the
specified interface(s) will be taken into account. The special target
'\@with_description' selects all interfaces with a non-empty description.
If an aggregated interface is encountered, the physical interfaces will
be checked as well.
* interface_forwarding: Check the forwarding state of interfaces as provided
by 'show ethernet-switching interfaces'. Storm control, MAC limit and
BPDUs will be considered CRITICAL states. If a target is specified, only
the specified interface(s) will be taken into account. Targets may be
specified as <interface_name>:<forwarding_state> in which case a CRITICAL
state is assumed if the specified interface is not in the specified state.
* chassis_environment: Check the status of verious system components
(as provided by 'show chassis environment'). If a target is specified,
only the specified component(s) will be taken into account. If specified,
the thresholds will be checked against the temperature of the components.
* system_storage: Check the amount of used space of system filesystems. If a
target is specified, only the specified filesystem(s) will be taken into
account (specified either by filesystem name or mount point). The
threshold will be checked against the amount (percent) of used space.
Warning and critical thresholds may be specified in the format documented at
http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT.",
);
my %checks = (
interfaces => \&check_interfaces,
interface_forwarding => \&check_interface_forwarding,
chassis_environment => \&check_chassis_environment,
system_storage => \&check_system_storage,
);
my $junos = undef;
my $cache = {};
$plugin->add_common_args();
$plugin->add_arg({
spec => 'caching|C',
usage => '-C, --caching',
desc => 'Enabling caching of API results',
default => 0,
});
foreach my $check (keys %checks) {
$plugin->add_check_impl($check, $checks{$check});
}
$plugin->set_default_check('chassis_environment');
# configure removes any options from @ARGV
$plugin->configure();
if ($plugin->{'conf'}->{'verbose'} > 3) {
JUNOS::Trace::init(1);
}
$plugin->set_checks(@ARGV);
$junos = $plugin->connect();
$plugin->run_checks();
my ($code, $msg) = $plugin->check_messages(join => ', ');
$plugin->nagios_exit($code, $msg);
sub check_interface
{
my $plugin = shift;
my $iface = shift;
my $opts = shift || {};
my @targets = @_;
my $name = $plugin->get_query_object_value($iface, 'name');
my $admin_status = $plugin->get_query_object_value($iface, 'admin-status');
if ($admin_status !~ m/^up$/) {
if ((grep { $name =~ m/^$_$/; } @targets)
|| ($opts->{'with_description'} &&
$plugin->get_query_object_value($iface, 'description'))) {
$plugin->add_message(CRITICAL,
"$name is not enabled");
return -1;
}
return 1;
}
if ($plugin->get_query_object_value($iface, 'oper-status') !~ m/^up$/i) {
return 0;
}
$plugin->add_perfdata(
label => "'$name-input-bytes'",
value => $plugin->get_query_object_value($iface,
['traffic-statistics', 'input-bytes']),
min => 0,
max => undef,
uom => 'B',
threshold => undef,
);
$plugin->add_perfdata(
label => "'$name-output-bytes'",
value => $plugin->get_query_object_value($iface,
['traffic-statistics', 'output-bytes']),
min => 0,
max => undef,
uom => 'B',
threshold => undef,
);
return 1;
}
sub get_interfaces
{
my $plugin = shift;
my $opts = shift || {};
my @targets = @_;
my @ifaces = ();
my @ret = ();
if (defined($cache->{'interfaces'})) {
@ifaces = @{$cache->{'interfaces'}};
}
else {
my $cmd = 'get_interface_information';
my $res;
my $args = { detail => 1 };
if ((scalar(@targets) == 1) && (! $opts->{'with_description'})
&& (! $plugin->{'conf'}->{'caching'})) {
$args->{'interface_name'} = $targets[0];
}
$res = $plugin->send_query($cmd, $args);
if (! ref $res) {
$plugin->die($res);
}
@ifaces = $res->getElementsByTagName('physical-interface');
}
if ($plugin->{'conf'}->{'caching'}) {
$cache->{'interfaces'} = \@ifaces;
}
@targets = map { s/\*/\.\*/g; s/\?/\./g; $_; } @targets;
if (scalar(@targets)) {
@ret = grep {
my $i = $_;
grep { $plugin->get_query_object_value($i, 'name') =~ m/^$_$/ } @targets;
} @ifaces;
}
elsif (! $opts->{'with_description'}) {
@ret = @ifaces;
}
if ($opts->{'with_description'}) {
foreach my $iface (@ifaces) {
my $name = $plugin->get_query_object_value($iface, 'name');
if ($plugin->get_query_object_value($iface, 'description')
&& (! grep { m/^$name$/; } @targets)) {
push @ret, $iface;
}
}
}
{
my @i = map { $plugin->get_query_object_value($_, 'name'). " => "
. $plugin->get_query_object_value($_, 'oper-status') } @ret;
$plugin->verbose(3, "Interfaces: " . join(", ", @i));
}
return @ret;
}
sub check_interfaces
{
my $plugin = shift;
my $junos = shift;
my $targets = shift || [];
my $exclude = shift || [];
my $opts = {
with_description => 0,
};
if (grep { m/^\@with_description$/; } @$targets) {
$opts->{'with_description'} = 1;
@$targets = grep { ! m/^\@with_description$/; } @$targets;
}
my @interfaces = get_interfaces($plugin, $opts, @$targets);;
my $down_count = 0;
my @down_ifaces = ();
my $phys_down_count = 0;
my @phys_down_ifaces = ();
my $have_lag_ifaces = 0;
foreach my $iface (@interfaces) {
my $name = $plugin->get_query_object_value($iface, 'name');
my $desc = $plugin->get_query_object_value($iface, 'description');
my $status;
if (grep { m/^$name$/ } @$exclude) {
next;
}
$status = check_interface($plugin, $iface, $opts, @$targets);
my $tmp;
if ($status == 0) {
++$down_count;
$tmp = $name . ($desc ? " ($desc)" : "");
push @down_ifaces, $tmp;
}
if ($status <= 0) {
# disabled or down
next;
}
if ($name !~ m/^ae/) {
next;
}
$have_lag_ifaces = 1;
my @markers = $plugin->get_query_object($iface,
['logical-interface', 'lag-traffic-statistics', 'lag-marker']);
if (! @markers) {
print STDERR "Cannot get marker for non-LACP interfaces yet!\n";
next;
}
foreach my $marker (@markers) {
my $phy_name = $plugin->get_query_object_value($marker, 'name');
$phy_name =~ s/\.\d+$//;
$plugin->verbose(3, "Quering physical interface '$phy_name' "
. "for $name.");
my @phy_interfaces = get_interfaces($plugin, {}, $phy_name);
foreach my $phy_iface (@phy_interfaces) {
if (check_interface($plugin, $phy_iface, {}, $phy_name) == 0) {
++$phys_down_count;
$tmp = $name . ($desc ? " ($desc)" : "");
push @phys_down_ifaces, "$tmp -> $phy_name";
}
}
}
}
if ($down_count > 0) {
$plugin->add_message(CRITICAL, $down_count . " interface"
. ($down_count == 1 ? "" : "s")
. " down (" . join(", ", @down_ifaces) . ")");
}
if ($phys_down_count > 0) {
$plugin->add_message(WARNING, $phys_down_count
. " LAG member interface"
. ($phys_down_count == 1 ? "" : "s")
. " down ("
. join(", ", @phys_down_ifaces) . ")");
}
if ((! $down_count) && (! $phys_down_count)) {
if ((! scalar(@$targets)) || $opts->{'with_description'}) {
$plugin->add_message(OK, "all interfaces up"
. ($have_lag_ifaces
? " (including all LAG member interfaces)" : ""));
}
else {
$plugin->add_message(OK, "interface"
. (scalar(@$targets) == 1 ? " " : "s ")
. join(", ", @$targets) . " up"
. ($have_lag_ifaces
? " (including all LAG member interfaces)" : ""));
}
}
}
sub check_interface_forwarding
{
my $plugin = shift;
my $junos = shift;
my $targets = shift || [];
my $exclude = shift || [];
my $res = $plugin->send_query('show ethernet-switching interfaces brief');
my %critical_map = (
'Disabled by bpdu-control' => 1,
'MAC limit exceeded' => 1,
'MAC move limit exceeded' => 1,
'Storm control in effect' => 1,
);
my %targets = map { my @t = split(':', $_); $t[0] => $t[1]; } @$targets;
my @failed = ();
{
my @i = map {
$plugin->get_query_object_value($_, 'interface-name')
. " => { " .
join(", ", map {
$plugin->get_query_object_value($_, 'blocking-status')
} $plugin->get_query_object($_,
['interface-vlan-member-list', 'interface-vlan-member']))
. " }"
} $plugin->get_query_object($res, 'interface');
$plugin->verbose(3, "Interfaces: " . join(", ", @i));
}
foreach my $iface ($plugin->get_query_object($res, 'interface')) {
my $name = $plugin->get_query_object_value($iface, 'interface-name');
my $failed_status = undef;
if (scalar(@$targets) && (! exists($targets{$name}))) {
next;
}
if (grep { m/^$name$/ } @$exclude) {
next;
}
foreach my $vlan_member ($plugin->get_query_object($iface,
['interface-vlan-member-list', 'interface-vlan-member'])) {
my $status = $plugin->get_query_object_value($vlan_member,
'blocking-status');
if (defined($targets{$name})) {
if ($status ne $targets{$name}) {
$failed_status = "$status (should: $targets{$name})";
last;
}
}
elsif (defined $critical_map{$status}) {
$failed_status = $status;
last;
}
}
if ($failed_status) {
push @failed, { name => $name, status => $failed_status };
}
}
if (scalar(@failed)) {
$plugin->add_message(CRITICAL, scalar(@failed) . " interface"
. (scalar(@failed) == 1 ? "" : "s")
. " blocked: "
. join(", ", map { "$_->{'name'}: $_->{'status'}" } @failed));
}
else {
$plugin->add_message(OK, "forwarding state of all interfaces OK");
}
}
sub check_chassis_environment
{
my $plugin = shift;
my $junos = shift;
my $targets = shift || [];
my $exclude = shift || [];
my $res = $plugin->send_query('get_environment_information');
my %status_map = (
OK => OK,
Testing => UNKNOWN,
Check => UNKNOWN,
Failed => CRITICAL,
Absent => CRITICAL,
);
my $items_count = 0;
my $items_ok = 0;
my $class = "";
foreach my $item ($plugin->get_query_object($res, 'environment-item')) {
my $name = $plugin->get_query_object_value($item, 'name');
if (scalar(@$targets) && (! grep { m/^$name$/ } @$targets)) {
next;
}
if (grep { m/^$name$/ } @$exclude) {
next;
}
if ($plugin->get_query_object_value($item, 'class')) {
$class = $plugin->get_query_object_value($item, 'class');
}
my $status = $plugin->get_query_object_value($item, 'status');
if ($status eq "Absent") {
if (! scalar(@$targets)) {
next;
}
# else: check this component
}
my $state = UNKNOWN;
if (defined $status_map{$status}) {
$state = $status_map{$status};
}
++$items_count;
if ($state == OK) {
++$items_ok;
}
else {
$plugin->add_message($state, $class . " $name: status " .
$status);
}
my $temp = $plugin->get_query_object_value($item, 'temperature');
if (! $temp) {
next;
}
($temp) = $temp =~ m/(\d+) degrees C/;
if (! defined($temp)) {
next;
}
$state = $plugin->check_threshold($temp);
if ($state != OK) {
$plugin->add_message($state, $class
. " $name: ${temp} degrees C");
}
my $label = "$name-temp";
$label =~ s/ /_/g;
$plugin->add_perfdata(
label => "'$label'",
value => $temp,
min => undef,
max => undef,
uom => '',
threshold => $plugin->threshold(),
);
}
if (! $items_count) {
$plugin->add_message(WARNING, "no components found");
}
elsif ($items_count == $items_ok) {
$plugin->add_message(OK, "$items_ok component"
. ($items_ok == 1 ? "" : "s")
. " OK");
}
else {
$plugin->add_message(WARNING,
"$items_ok / $items_count components OK");
}
}
sub check_system_storage
{
my $plugin = shift;
my $junos = shift;
my $targets = shift || [];
my $exclude = shift || [];
my $res = $plugin->send_query('get_system_storage');
my $all_ok = 1;
foreach my $re ($plugin->get_query_object($res,
'multi-routing-engine-item')) {
my $re_name = $plugin->get_query_object_value($re, 're-name');
foreach my $fs ($plugin->get_query_object($re,
['system-storage-information', 'filesystem'])) {
my $name = $plugin->get_query_object_value($fs, 'filesystem-name');
my $mnt_pt = $plugin->get_query_object_value($fs, 'mounted-on');
if (scalar(@$targets) && (! grep { m/^$name$/ } @$targets)
&& (! grep { m/^$mnt_pt$/ } @$targets)) {
next;
}
if (grep { m/^$mnt_pt$/ } @$exclude) {
next;
}
my $used = $plugin->get_query_object_value($fs, 'used-percent') + 0;
my $state = $plugin->check_threshold($used);
if ($state != OK) {
$all_ok = 0;
$plugin->add_message($state, "$re_name $mnt_pt: "
. "$used\% used");
}
$plugin->add_perfdata(
label => "'$re_name-$mnt_pt'",
value => $used,
min => 0,
max => 100,
uom => '%',
threshold => $plugin->threshold(),
);
}
}
if ($all_ok) {
$plugin->add_message(OK, "all filesystems within thresholds");
}
}

View file

@ -1,581 +0,0 @@
#!/usr/bin/perl
#############################################################################
# (c) 2001, 2003 Juniper Networks, Inc. #
# (c) 2011 Sebastian "tokkee" Harl <sh@teamix.net> #
# and team(ix) GmbH, Nuernberg, Germany #
# #
# This file is part of "team(ix) Monitoring Plugins" #
# URL: http://oss.teamix.org/projects/monitoringplugins/ #
# #
# All rights reserved. #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions #
# are met: #
# 1. Redistributions of source code must retain the above copyright #
# notice, this list of conditions and the following disclaimer. #
# 2. Redistributions in binary form must reproduce the above copyright #
# notice, this list of conditions and the following disclaimer in the #
# documentation and/or other materials provided with the distribution. #
# 3. The name of the copyright owner may not be used to endorse or #
# promote products derived from this software without specific prior #
# written permission. #
# #
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR #
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE #
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, #
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES #
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR #
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) #
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, #
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING #
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE #
# POSSIBILITY OF SUCH DAMAGE. #
#############################################################################
use strict;
use warnings;
use utf8;
use Data::Dumper;
use POSIX qw( :termios_h );
use Nagios::Plugin;
use Regexp::Common;
use Regexp::IPv6 qw( $IPv6_re );
use JUNOS::Device;
binmode STDOUT, ":utf8";
my $valid_checks = "peers_count|prefix_count";
my $plugin = Nagios::Plugin->new(
plugin => 'check_junos_bgp',
shortname => 'check_junos_bgp',
version => '0.1',
url => 'http://oss.teamix.org/projects/monitoringplugins',
blurb => 'Monitor Juniper™ Router\'s BGP tables.',
usage =>
"Usage: %s [-v|--verbose] [-t <timeout] \
[-H <host>] [-p <port>] [-U <user>] [-P <password] \
[-L <logical-system-name>] [-I <name of instance>] check-tuple [...] ",
license =>
"This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY.
It may be used, redistributed and/or modified under the terms of the 3-Clause
BSD License (see http://opensource.org/licenses/BSD-3-Clause).",
extra => "
This plugin connects to a Juniper Router device and requests BGP table
information using the 'show bgp neighbor' command. It then checks the
specified thresholds depending on the specified checks.
A check-tuple consists of the name of the check and, optionally, a \"target\"
(e.g., peer address), and warning and critical thresholds:
checkname[,target[,warning[,critical]]]
The following checks are available:
* peers_count: Total number of peers. If a target is specified, only peers
matching that target are taken into account.
* prefix_count: Number of active prefixes for a single peer. If multiple
peers match the specified target, each of those is checked against the
specified thresholds.
Targets are either specified as IPv4/IPv6 addresses or regular expressions /
strings. In the former case, the target is compared against the peer's
address, else against the peer's description. When specifying regular
expressions, they have to be enclosed in '/'. Else, the pattern is treated as
verbatim string that has to be matched.
Warning and critical thresholds may be specified in the format documented at
http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT.",
);
# Predefined arguments (by Nagios::Plugin)
my @predefined_args = qw(
usage
help
version
extra-opts
timeout
verbose
);
my @args = (
{
spec => 'host|H=s',
usage => '-H, --host=HOSTNAME',
desc => 'Hostname/IP of Juniper box to connect to',
default => 'localhost',
},
{
spec => 'port|p=i',
usage => '-p, --port=PORT',
desc => 'Port to connect to',
default => 22,
},
{
spec => 'user|U=s',
usage => '-U, --user=USERNAME',
desc => 'Username to log into box as',
default => 'root',
},
{
spec => 'password|P=s',
usage => '-P, --password=PASSWORD',
desc => 'Password for login username',
default => '<prompt>',
},
{
spec => 'logical-router|L=s',
usage => '-L, --logical-router=ROUTER',
desc => 'Logical Router',
default => '',
},
{
spec => 'instance|I=s',
usage => '-I, --instance=INSTANCE',
desc => 'Instance',
default => '',
},
);
my %conf = ();
my $junos = undef;
my $neigh_info = undef;
my @peers = ();
foreach my $arg (@args) {
add_arg($plugin, $arg);
}
$plugin->getopts;
# Initialize this first, so it may be used right away.
$conf{'verbose'} = $plugin->opts->verbose;
foreach my $arg (@args) {
my @c = get_conf($plugin, $arg);
$conf{$c[0]} = $c[1];
}
foreach my $arg (@predefined_args) {
$conf{$arg} = $plugin->opts->$arg;
}
add_checks(\%conf, @ARGV);
if (! $plugin->opts->password) {
my $term = POSIX::Termios->new();
my $lflag;
print "Password: ";
$term->getattr(fileno(STDIN));
$lflag = $term->getlflag;
$term->setlflag($lflag & ~POSIX::ECHO);
$term->setattr(fileno(STDIN), TCSANOW);
$conf{'password'} = <STDIN>;
chomp($conf{'password'});
$term->setlflag($lflag | POSIX::ECHO);
$term->setattr(fileno(STDIN), TCSAFLUSH);
print "\n";
}
verbose(1, "Connecting to host $conf{'host'} as user $conf{'user'}.");
$junos = JUNOS::Device->new(
hostname => $conf{'host'},
login => $conf{'user'},
password => $conf{'password'},
access => 'ssh',
'ssh-compress' => 0);
if (! ref $junos) {
$plugin->die("ERROR: failed to connect to " . $conf{'host'} . "!");
}
verbose(1, "Querying BGP neighbor information.");
$neigh_info = get_neighbor_information($junos);
if (! ref $neigh_info) {
$plugin->die($neigh_info);
}
@peers = $neigh_info->getElementsByTagName('bgp-peer');
if ($conf{'verbose'} >= 3) {
my @p = map { (get_peer_address($_) // "<unknown address>")
. " => " . (get_peer_description($_) // "<unknown description>") } @peers;
verbose(3, "Peers: " . join(", ", @p));
}
foreach my $check (@{$conf{'checks'}}) {
my $code;
my $value;
my @relevant_peers = get_relevant_peers($check, @peers);
if ($conf{'verbose'} >= 2) {
my @p = map { (get_peer_address($_) // "<unknown address>")
. " => " . (get_peer_description($_) // "<unknown description>") } @relevant_peers;
verbose(2, "Relevant peers: " . join(", ", @p));
}
$plugin->set_thresholds(
warning => $check->{'warning'},
critical => $check->{'critical'},
);
if ($check->{'name'} eq 'peers_count') {
$value = scalar(@relevant_peers);
$code = $plugin->check_threshold($value);
$plugin->add_message($code, "$value peer" . (($value == 1) ? "" : "s"));
$plugin->add_perfdata(
label => 'peers_count',
value => $value,
min => 0,
max => undef,
uom => '',
threshold => $plugin->threshold(),
);
}
elsif ($check->{'name'} eq 'prefix_count') {
foreach my $peer (@relevant_peers) {
my $peer_addr = get_peer_address($peer);
if (! defined($peer_addr)) {
$peer_addr = "<unknown address>";
}
$value = get_peer_element($peer, 'peer-state');
if (! defined($value)) {
$value = "<unknown state>";
}
verbose(2, "Peer $peer_addr: peer-state = $value.");
if ($value eq 'Established') {
$value = $peer->getElementsByTagName('bgp-rib');
$value = get_peer_element($value->[0], 'active-prefix-count');
if (! $value) {
$value = 0;
}
$code = $plugin->check_threshold($value);
$plugin->add_message($code, "peer $peer_addr: $value prefix"
. (($value == 1) ? "" : "es"));
verbose(2, "Peer $peer_addr: active-prefix-count = $value.");
}
else {
$value = "";
$code = CRITICAL;
$plugin->add_message($code,
"peer $peer_addr: no established connection");
}
$plugin->add_perfdata(
label => '\'prefix_count[' . $peer_addr . ']\'',
value => $value,
min => 0,
max => undef,
uom => '',
threshold => $plugin->threshold(),
);
}
}
}
my ($code, $msg) = $plugin->check_messages(join => ', ');
$junos->disconnect();
$plugin->nagios_exit($code, $msg);
sub send_query
{
my $device = shift;
my $query = shift;
my $queryargs = shift;
my $res;
my $err;
verbose(3, "Sending query '$query' to router.");
if (ref $queryargs) {
$res = $device->$query(%$queryargs);
} else {
$res = $device->$query();
}
verbose(5, "Got response: " . Dumper(\$res));
if (! ref $res) {
return "ERROR: Failed to execute query '$query'";
}
$err = $res->getFirstError();
if ($err) {
return "ERROR: " . $err->{message};
}
return $res;
}
sub get_neighbor_information
{
my $device = shift;
my @table;
my $query = "get_bgp_summary_information";
my $res;
my %args;
if (($conf{'logical-router'} ne '') || ($conf{'instance'} ne '')) {
if ($conf{'logical-router'} ne '') {
$args{'logical-router'} = $conf{'logical-router'};
}
if ($conf{'instance'} ne '') {
$args{'instance'} = $conf{'instance'};
}
$res = send_query($device, $query, \%args);
} else {
$res = send_query($device, $query);
}
my $err;
if (! ref $res) {
return $res;
}
$err = $res->getFirstError();
if ($err) {
return "ERROR: " . $err->{message};
}
return $res;
}
sub add_arg
{
my $plugin = shift;
my $arg = shift;
my $spec = $arg->{'spec'};
my $help = $arg->{'usage'};
if (defined $arg->{'desc'}) {
my @desc;
if (ref($arg->{'desc'})) {
@desc = @{$arg->{'desc'}};
}
else {
@desc = ( $arg->{'desc'} );
}
foreach my $d (@desc) {
$help .= "\n $d";
}
if (defined $arg->{'default'}) {
$help .= " (default: $arg->{'default'})";
}
}
elsif (defined $arg->{'default'}) {
$help .= "\n (default: $arg->{'default'})";
}
$plugin->add_arg(
spec => $spec,
help => $help,
);
}
sub get_conf
{
my $plugin = shift;
my $arg = shift;
my ($name, undef) = split(m/\|/, $arg->{'spec'});
my $value = $plugin->opts->$name || $arg->{'default'};
if ($name eq 'password') {
verbose(3, "conf: password => "
. (($value eq '<prompt>') ? '<prompt>' : '<hidden>'));
}
else {
verbose(3, "conf: $name => $value");
}
return ($name => $value);
}
sub add_single_check
{
my $conf = shift;
my @check = split(m/,/, shift);
my %c = ();
if ($check[0] !~ m/\b(?:$valid_checks)\b/) {
return "ERROR: invalid check '$check[0]'";
}
$c{'name'} = $check[0];
if ((! defined($check[1])) || ($check[1] eq "")) {
$c{'target'} = qr//,
$c{'ttype'} = 'address',
}
elsif ($check[1] =~ m/^(?:$RE{'net'}{'IPv4'}|$IPv6_re)$/) {
$c{'target'} = $check[1];
$c{'ttype'} = 'address';
}
elsif ($check[1] =~ m/^\/(.*)\/$/) {
$c{'target'} = qr/$1/;
$c{'ttype'} = 'description';
}
else {
$c{'target'} = $check[1];
$c{'ttype'} = 'description';
}
$c{'warning'} = $check[2];
$c{'critical'} = $check[3];
# check for valid thresholds
# set_threshold() will die if any threshold is not valid
$plugin->set_thresholds(
warning => $c{'warning'},
critical => $c{'critical'},
) || $plugin->die("ERROR: Invalid thresholds: "
. "warning => $c{'warning'}, critical => $c{'critical'}");
push @{$conf->{'checks'}}, \%c;
}
sub add_checks
{
my $conf = shift;
my @checks = @_;
my $err_str = "ERROR:";
if (scalar(@checks) == 0) {
$conf->{'checks'}[0] = {
name => 'peers_count',
target => qr//,
ttype => 'address',
warning => undef,
critical => undef,
};
return 1;
}
$conf->{'checks'} = [];
foreach my $check (@checks) {
my $e;
$e = add_single_check($conf, $check);
if ($e =~ m/^ERROR: (.*)$/) {
$err_str .= " $1,";
}
}
if ($err_str ne "ERROR:") {
$err_str =~ s/,$//;
$plugin->die($err_str);
}
}
sub get_relevant_peers
{
my $check = shift;
my @peers = @_;
my @rpeers = ();
my $cmp = sub {
my ($a, $b, undef) = @_;
if (ref $b) {
my $r = $a =~ $b;
verbose(3, "Checking peer '$a' against regex '$b' -> "
. ($r ? "true" : "false") . ".");
return $r;
}
else {
my $r = $a eq $b;
verbose(3, "Comparing peer '$a' with string '$b' -> "
. ($r ? "true" : "false") . ".");
return $r;
}
};
my $get_peer_elem;
if ($check->{'ttype'} eq 'description') {
$get_peer_elem = \&get_peer_description;
}
else {
$get_peer_elem = \&get_peer_address;
}
@rpeers = grep { $cmp->($get_peer_elem->($_), $check->{'target'}) } @peers;
return @rpeers;
}
sub get_peer_element
{
my $peer = shift;
my $elem = shift;
my $e;
if (! $peer) {
print STDERR "Cannot retrieve element '$elem' "
. "from undefined value.\n";
return;
}
$e = $peer->getElementsByTagName($elem);
if ((! $e) || (! $e->item(0))) {
print STDERR "Attribute '$elem' not found for peer.\n";
verbose(4, "Peer was: " . Dumper($peer));
return;
}
return $e->item(0)->getFirstChild->getNodeValue;
}
sub get_peer_description
{
my $peer = shift;
return get_peer_element($peer, 'description');
}
sub get_peer_address
{
my $peer = shift;
return get_peer_element($peer, 'peer-address');
}
sub verbose
{
my $level = shift;
my @msgs = @_;
if ($level > $conf{'verbose'}) {
return;
}
foreach my $msg (@msgs) {
print "V$level: $msg\n";
}
}

View file

@ -1,836 +0,0 @@
#!/usr/bin/perl
#############################################################################
# (c) 2001, 2003 Juniper Networks, Inc. #
# (c) 2011 Sebastian "tokkee" Harl <sh@teamix.net> #
# and team(ix) GmbH, Nuernberg, Germany #
# #
# This file is part of "team(ix) Monitoring Plugins" #
# URL: http://oss.teamix.org/projects/monitoringplugins/ #
# #
# All rights reserved. #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions #
# are met: #
# 1. Redistributions of source code must retain the above copyright #
# notice, this list of conditions and the following disclaimer. #
# 2. Redistributions in binary form must reproduce the above copyright #
# notice, this list of conditions and the following disclaimer in the #
# documentation and/or other materials provided with the distribution. #
# 3. The name of the copyright owner may not be used to endorse or #
# promote products derived from this software without specific prior #
# written permission. #
# #
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR #
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE #
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, #
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES #
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR #
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) #
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, #
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING #
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE #
# POSSIBILITY OF SUCH DAMAGE. #
#############################################################################
use strict;
use warnings;
use utf8;
use Data::Dumper;
use POSIX qw( :termios_h );
use Nagios::Plugin;
use JUNOS::Device;
binmode STDOUT, ":utf8";
my $valid_checks = "members_count|master|backup|interfaces|version";
# TODO:
# (on newer JUNOS (10.4r5.5))
# request chassis routing-engine master switch check
# -> graceful switchover status
my $plugin = Nagios::Plugin->new(
plugin => 'check_junos_vc',
shortname => 'check_junos_vc',
version => '0.1',
url => 'http://oss.teamix.org/projects/monitoringplugins',
blurb => 'Monitor Juniper™ Switch Virtual Chassis.',
usage =>
"Usage: %s [-v|--verbose] [-H <host>] [-p <port>] [-t <timeout]
[-U <user>] [-P <password] check-tuple [...]",
license =>
"This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY.
It may be used, redistributed and/or modified under the terms of the 3-Clause
BSD License (see http://opensource.org/licenses/BSD-3-Clause).",
extra => "
This plugin connects to a Juniper Switch device and and checks Virtual
Chassis information.
A check-tuple consists of the name of the check and, optionally, a \"target\"
which more closely specifies which characteristics should be checked, and
warning and critical thresholds:
checkname[,target[,warning[,critical]]]
The following checks are available:
* members_count: Total number of members in the Virtual Chassis. If a target
is specified, only peers whose status (NotPrsnt, Prsnt) matches one of the
specified targets are taken into account.
* master, backup: Check the number or assignment of master resp. backup
members. If a target is specified, check that those members whose serial
number matches the specified target have the requested role (master,
backup) assigned to them. Else, check the number of master resp. backup
members against the specified thresholds.
* interfaces: Check that all VCP interfaces are up. If warning or critical
thresholds have been specified, also check the number of VCP interfaces
against the thresholds.
* version: Check the version of all physically connected members.
Warning and critical thresholds may be specified in the format documented at
http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT.",
);
# Predefined arguments (by Nagios::Plugin)
my @predefined_args = qw(
usage
help
version
extra-opts
timeout
verbose
);
my @args = (
{
spec => 'host|H=s',
usage => '-H, --host=HOSTNAME',
desc => 'Hostname/IP of Juniper box to connect to',
default => 'localhost',
},
{
spec => 'port|p=i',
usage => '-p, --port=PORT',
desc => 'Port to connect to',
default => 22,
},
{
spec => 'user|U=s',
usage => '-U, --user=USERNAME',
desc => 'Username to log into box as',
default => 'root',
},
{
spec => 'password|P=s',
usage => '-P, --password=PASSWORD',
desc => 'Password for login username',
default => '<prompt>',
},
);
my %conf = ();
my $junos = undef;
foreach my $arg (@args) {
add_arg($plugin, $arg);
}
$plugin->getopts;
# Initialize this first, so it may be used right away.
$conf{'verbose'} = $plugin->opts->verbose;
foreach my $arg (@args) {
my @c = get_conf($plugin, $arg);
$conf{$c[0]} = $c[1];
}
foreach my $arg (@predefined_args) {
$conf{$arg} = $plugin->opts->$arg;
}
add_checks(\%conf, @ARGV);
if (! $plugin->opts->password) {
my $term = POSIX::Termios->new();
my $lflag;
print "Password: ";
$term->getattr(fileno(STDIN));
$lflag = $term->getlflag;
$term->setlflag($lflag & ~POSIX::ECHO);
$term->setattr(fileno(STDIN), TCSANOW);
$conf{'password'} = <STDIN>;
chomp($conf{'password'});
$term->setlflag($lflag | POSIX::ECHO);
$term->setattr(fileno(STDIN), TCSAFLUSH);
print "\n";
}
verbose(1, "Connecting to host $conf{'host'} as user $conf{'user'}.");
$junos = JUNOS::Device->new(
hostname => $conf{'host'},
login => $conf{'user'},
password => $conf{'password'},
access => 'ssh',
'ssh-compress' => 0);
if (! ref $junos) {
$plugin->die("ERROR: failed to connect to " . $conf{'host'} . "!");
}
my $vc = undef;
my @vc_members = ();
my $have_vc_members = 0;
foreach my $check (@{$conf{'checks'}}) {
my $code;
my $value;
my @targets = ();
if (defined $check->{'target'}) {
@targets = @{$check->{'target'}};
}
$plugin->set_thresholds(
warning => $check->{'warning'},
critical => $check->{'critical'},
);
if ($check->{'name'} eq 'members_count') {
my @relevant_members = ();
my $value = 0;
my $code;
@vc_members = get_vc_members($junos);
if (scalar(@targets)) {
foreach my $member (@vc_members) {
my $role = get_member_status($member);
if (scalar(grep { $role eq $_ } @targets)) {
push @relevant_members, $member;
$value++;
}
}
}
else {
@relevant_members = @vc_members;
$value = scalar(@vc_members);
}
$code = $plugin->check_threshold($value);
$plugin->add_message($code, "$value " . join(" + ", @targets)
. " member" . (($value == 1) ? "" : "s"));
my $label = 'members';
if (scalar(@targets)) {
$label .= '[' . join('+', @targets) . ']';
}
$plugin->add_perfdata(
label => $label,
value => $value,
min => 0,
max => undef,
uom => '',
threshold => $plugin->threshold(),
);
}
elsif (($check->{'name'} eq 'master') || ($check->{'name'} eq 'backup')) {
my $wanted_role = ($check->{'name'} eq 'master')
? 'Master' : 'Backup';
my @wanted_members = ();
my $value;
my $code;
@vc_members = get_vc_members($junos);
foreach my $member (@vc_members) {
my $role = get_member_role($member);
if ($role eq $wanted_role) {
push @wanted_members, $member;
}
}
if (scalar(@targets)) {
my @ok_targets = ();
my @fail_targets = ();
$code = UNKNOWN;
foreach my $target (@targets) {
if (scalar(grep { $target eq get_member_serial($_) } @wanted_members)) {
# requested target does have wanted role assigned
if (($code == UNKNOWN) || ($code == OK)) {
$code = OK;
}
else {
# we've had previous errors
$code = WARNING;
}
push @ok_targets, $target;
}
else {
if (($code == OK) || ($code == WARNING)) {
# we've had previous success
$code = WARNING;
}
else {
$code = CRITICAL;
}
push @fail_targets, $target;
}
}
$plugin->add_message($code, scalar(@fail_targets)
. " missing/failed-over " . $check->{'name'}
. ((scalar(@fail_targets) == 1) ? "" : "s")
. (scalar(@fail_targets)
? " (" . join(", ", @fail_targets) . ")" : "")
. ", " . scalar(@ok_targets) . " active " . $check->{'name'}
. ((scalar(@ok_targets) == 1) ? "" : "s")
. (scalar(@ok_targets)
? " (" . join(", ", @ok_targets) . ")" : ""));
$plugin->add_perfdata(
label => 'active_' . $check->{'name'},
value => scalar(@ok_targets),
min => 0,
max => undef,
uom => '',
threshold => undef,
);
$plugin->add_perfdata(
label => 'failed_' . $check->{'name'},
value => scalar(@fail_targets),
min => 0,
max => undef,
uom => '',
threshold => undef,
);
}
else {
$value = scalar @wanted_members;
$code = $plugin->check_threshold($value);
$plugin->add_message($code, "$value " . $check->{'name'} . " member"
. (($value == 1) ? "" : "s"));
$plugin->add_perfdata(
label => $check->{'name'},
value => $value,
min => 0,
max => undef,
uom => '',
threshold => $plugin->threshold(),
);
}
}
elsif ($check->{'name'} eq 'interfaces') {
my @up_ifaces = ();
my @down_ifaces = ();
my @vc_interfaces = get_vc_interfaces($junos);
foreach my $iface (@vc_interfaces) {
my $status = get_iface_status($iface);
if ($status eq 'up') {
push @up_ifaces, get_iface_name($iface);
next;
}
# else:
push @down_ifaces, {
name => get_iface_name($iface),
status => $status,
};
}
if (scalar(@down_ifaces)) {
$plugin->add_message(CRITICAL, scalar(@down_ifaces)
. " VCP interface" . ((scalar(@down_ifaces) == 1) ? "" : "s")
. " not up ("
. join(", ",
map { "$_->{'name'} $_->{'status'}" } @down_ifaces)
. ")");
}
elsif ($check->{'warning'} || $check->{'critical'}) {
my $value = scalar @vc_interfaces;
my $code = $plugin->check_threshold($value);
$plugin->add_message($code, "$value VCP interface"
. (($value == 1) ? "" : "s") . " found ("
. scalar(@up_ifaces) . " up, "
. scalar(@down_ifaces) . " down)");
}
elsif (! scalar(@up_ifaces)) {
# no VCP interfaces at all
$plugin->add_message(CRITICAL, "no VCP interfaces found");
}
else {
$plugin->add_message(OK, "all VCP interfaces up");
}
$plugin->add_perfdata(
label => 'vcp_interfaces',
value => scalar(@vc_interfaces),
min => 0,
max => undef,
uom => '',
threshold => $plugin->threshold(),
);
$plugin->add_perfdata(
label => 'up_interfaces',
value => scalar(@up_ifaces),
min => 0,
max => undef,
uom => '',
threshold => undef,
);
$plugin->add_perfdata(
label => 'down_interfaces',
value => scalar(@down_ifaces),
min => 0,
max => undef,
uom => '',
threshold => undef,
);
}
elsif ($check->{'name'} eq 'version') {
my %versions = get_versions($junos);
my @v_keys = keys %versions;
my $first = undef;
my @base_mismatch = ();
my %mismatches = ();
foreach my $k (@v_keys) {
my $base = $versions{$k}->{'base'};
my $other = $versions{$k}->{'other'};
foreach my $o (keys %$other) {
if ($other->{$o} ne $base) {
$mismatches{$k}->{$base} = 1;
$mismatches{$k}->{$other->{$o}} = 1;
}
}
}
$first = shift @v_keys;
$first = $versions{$first};
foreach my $k (@v_keys) {
if ($first->{'base'} ne $versions{$k}->{'base'}) {
push @base_mismatch, $k;
}
}
if (scalar @base_mismatch) {
my @first_match = grep {
$versions{$_}->{'base'} eq $first->{'base'}
} keys %versions;
my %mismatches = ();
foreach my $m (@base_mismatch) {
push @{$mismatches{$versions{$m}->{'base'}}}, $m;
}
$plugin->add_message(CRITICAL, "version mismatch detected: "
. $first->{'base'} . " @ ("
. join(", ", @first_match) . ") != "
. join(" != ", map {
$_ . " @ (" . join(", ", @{$mismatches{$_}}) . ")"
} keys %mismatches));
}
elsif (scalar(keys %mismatches)) {
$plugin->add_message(WARNING, "version mismatches detected: "
. join(" / ", map {
"$_: " . join(" != ", keys %{$mismatches{$_}})
} keys %mismatches));
}
else {
$plugin->add_message(OK, "all members at version "
. $first->{'base'});
}
}
}
# add total numbers to perfdata to ease graphing stuff
if ($have_vc_members) {
$plugin->add_perfdata(
label => 'members',
value => scalar(@vc_members),
min => 0,
max => undef,
uom => '',
threshold => undef,
);
}
my ($code, $msg) = $plugin->check_messages(join => ', ');
$junos->disconnect();
$plugin->nagios_exit($code, $msg);
sub send_query
{
my $device = shift;
my $query = shift;
my $queryargs = shift;
my $res;
my $err;
verbose(3, "Sending query '$query' to router.");
if (ref $queryargs) {
$res = $device->$query(%$queryargs);
} else {
$res = $device->$query();
}
verbose(5, "Got response: " . Dumper(\$res));
if (! ref $res) {
return "ERROR: Failed to execute query '$query'";
}
$err = $res->getFirstError();
if ($err) {
return "ERROR: " . $err->{message};
}
return $res;
}
sub send_command
{
my $device = shift;
my $cmd = shift;
my $res;
my $err;
verbose(3, "Sending command '$cmd' to router.");
$res = $device->command($cmd);
if (! ref $res) {
return "ERROR: Failed to execute command '$cmd'";
}
$err = $res->getFirstError();
if ($err) {
return "ERROR: " . $err->{message};
}
return $res;
}
sub get_vc_information
{
my $device = shift;
my $cmd = "show virtual-chassis status";
my $res = send_command($device, $cmd);
my $err;
if (! ref $res) {
return $res;
}
return $res;
}
sub get_vc_members
{
my $device = shift;
if ($have_vc_members) {
return @vc_members;
}
$vc = get_vc_information($device);
if (! ref $vc) {
$plugin->die($vc);
}
my $vc_id = ($vc->getElementsByTagName('virtual-chassis-id-information'))[0];
$vc_id = ($vc_id->getElementsByTagName('virtual-chassis-id'))[0];
$vc_id = $vc_id->getFirstChild->getNodeValue;
verbose(3, "Analyzing data from virtual chassis $vc_id.");
@vc_members = ($vc->getElementsByTagName('member-list'))[0]->getElementsByTagName('member');
if ($conf{'verbose'} >= 3) {
my @m = map { get_member_id($_) . " => " . get_member_serial($_) }
@vc_members;
verbose(3, "Members: " . join(", ", @m));
}
$have_vc_members = 1;
return @vc_members;
}
sub get_vc_interfaces
{
my $device = shift;
my @ifaces = ();
my $cmd = "get_interface_information";
my %args = ( interface_name => 'vcp*' );
my $res = send_query($device, $cmd, \%args);
if (! ref $res) {
$plugin->die($res);
}
@ifaces = $res->getElementsByTagName('physical-interface');
if ($conf{'verbose'} >= 3) {
my @i = map { get_iface_name($_) . " => " . get_iface_status($_) }
@ifaces;
verbose(3, "VCP Interfaces: " . join(", ", @i));
}
return @ifaces;
}
sub get_versions
{
my $device = shift;
my %versions = ();
my $cmd = "show version";
my $res = send_command($device, $cmd);
my @v = ();
if (! ref $res) {
$plugin->die($res);
}
@v = $res->getElementsByTagName('multi-routing-engine-item');
foreach my $i (@v) {
my $name = get_obj_element($i, 're-name');
my @infos = $i->getElementsByTagName('software-information');
@infos = $infos[0]->getElementsByTagName('package-information');
foreach my $j (@infos) {
my $comment = get_obj_element($j, 'comment');
my ($desc, $version);
$comment =~ m/^(.*) \[([^]]+)\]$/;
$desc = $1;
$version = $2;
if ($desc eq "JUNOS Base OS boot") {
$versions{$name}->{'base'} = $version;
}
else {
$versions{$name}->{'other'}->{$desc} = $version;
}
}
}
return %versions;
}
sub add_arg
{
my $plugin = shift;
my $arg = shift;
my $spec = $arg->{'spec'};
my $help = $arg->{'usage'};
if (defined $arg->{'desc'}) {
my @desc;
if (ref($arg->{'desc'})) {
@desc = @{$arg->{'desc'}};
}
else {
@desc = ( $arg->{'desc'} );
}
foreach my $d (@desc) {
$help .= "\n $d";
}
if (defined $arg->{'default'}) {
$help .= " (default: $arg->{'default'})";
}
}
elsif (defined $arg->{'default'}) {
$help .= "\n (default: $arg->{'default'})";
}
$plugin->add_arg(
spec => $spec,
help => $help,
);
}
sub get_conf
{
my $plugin = shift;
my $arg = shift;
my ($name, undef) = split(m/\|/, $arg->{'spec'});
my $value = $plugin->opts->$name || $arg->{'default'};
if ($name eq 'password') {
verbose(3, "conf: password => "
. (($value eq '<prompt>') ? '<prompt>' : '<hidden>'));
}
else {
verbose(3, "conf: $name => $value");
}
return ($name => $value);
}
sub add_single_check
{
my $conf = shift;
my @check = split(m/,/, shift);
my %c = ();
if ($check[0] !~ m/\b(?:$valid_checks)\b/) {
return "ERROR: invalid check '$check[0]'";
}
$c{'name'} = $check[0];
$c{'target'} = undef;
if (defined($check[1])) {
$c{'target'} = [ split(m/\+/, $check[1]) ];
}
$c{'warning'} = $check[2];
$c{'critical'} = $check[3];
# check for valid thresholds
# set_threshold() will die if any threshold is not valid
$plugin->set_thresholds(
warning => $c{'warning'},
critical => $c{'critical'},
) || $plugin->die("ERROR: Invalid thresholds: "
. "warning => $c{'warning'}, critical => $c{'critical'}");
push @{$conf->{'checks'}}, \%c;
}
sub add_checks
{
my $conf = shift;
my @checks = @_;
my $err_str = "ERROR:";
if (scalar(@checks) == 0) {
$conf->{'checks'}[0] = {
name => 'members_count',
target => [],
warning => undef,
critical => undef,
};
return 1;
}
$conf->{'checks'} = [];
foreach my $check (@checks) {
my $e;
$e = add_single_check($conf, $check);
if ($e =~ m/^ERROR: (.*)$/) {
$err_str .= " $1,";
}
}
if ($err_str ne "ERROR:") {
$err_str =~ s/,$//;
$plugin->die($err_str);
}
}
sub get_obj_element
{
my $obj = shift;
my $elem = shift;
$elem = $obj->getElementsByTagName($elem);
return $elem->item(0)->getFirstChild->getNodeValue;
}
sub get_member_id
{
my $member = shift;
return get_obj_element($member, 'member-id');
}
sub get_member_serial
{
my $member = shift;
return get_obj_element($member, 'member-serial-number');
}
sub get_member_status
{
my $member = shift;
return get_obj_element($member, 'member-status');
}
sub get_member_role
{
my $member = shift;
my $elem;
$elem = $member->getElementsByTagName('member-role');
if ($elem && $elem->item(0)) {
$elem = $elem->item(0)->getFirstChild->getNodeValue;
# e.g., '*' may be appended to the member-role
$elem =~ s/\W//g;
return $elem;
}
else {
return "";
}
}
sub get_iface_name
{
my $iface = shift;
return get_obj_element($iface, 'name');
}
sub get_iface_status
{
my $iface = shift;
return get_obj_element($iface, 'oper-status');
}
sub verbose
{
my $level = shift;
my @msgs = @_;
if ($level > $conf{'verbose'}) {
return;
}
foreach my $msg (@msgs) {
print "V$level: $msg\n";
}
}

View file

@ -1,262 +0,0 @@
#!/usr/bin/perl
#####################################################################
# (c) 2012 Sebastian "tokkee" Harl <sh@teamix.net> #
# and team(ix) GmbH, Nuernberg, Germany #
# #
# This file is part of "team(ix) Monitoring Plugins" #
# URL: http://oss.teamix.org/projects/monitoringplugins/ #
# #
# This file is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published #
# by the Free Software Foundation, either version 2 of the License, #
# or (at your option) any later version. #
# #
# This file is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this file. If not, see <http://www.gnu.org/licenses/>. #
#####################################################################
use strict;
use warnings;
use utf8;
use FindBin qw( $Bin );
use lib "$Bin/perl/lib";
use Nagios::Plugin::NetApp;
binmode STDOUT, ":utf8";
my $plugin = Nagios::Plugin::NetApp->new(
plugin => 'check_naf_exports',
shortname => 'check_naf_exports',
version => '0.1',
url => 'http://oss.teamix.org/projects/monitoringplugins',
blurb => 'Monitor NetApp™ NFS exports.',
usage =>
"Usage: %s [-v|--verbose] [-H <host>] [-p <port>] [-t <timeout]
[-U <user>] [-P <password] check-tuple [...]",
license =>
"This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY.
It may be used, redistributed and/or modified under the terms of the GNU
General Public License, either version 2 or (at your option) any later version
(see http://opensource.org/licenses/GPL-2.0).",
extra => "
This plugin connects to a NetApp filer and checks NFS exports related issues.
A check-tuple consists of the name of the check and, optionally, a \"target\"
which more closely specifies which characteristics should be checked, and
warning and critical thresholds:
checkname[,target[,warning[,critical]]]
The following checks are available:
* exportfs_consistent: Check if /etc/exports is consistent with the currently
exported filessytems.
Warning and critical thresholds may be specified in the format documented at
http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT.",
);
my %checks = (
exportfs_consistent => \&check_exportfs_consistent,
);
my $srv = undef;
$plugin->add_common_args();
foreach my $check (keys %checks) {
$plugin->add_check_impl($check, $checks{$check});
}
$plugin->set_default_check('exportfs_consistent');
# configure removes any options from @ARGV
$plugin->configure();
$plugin->set_checks(@ARGV);
$srv = $plugin->connect();
$plugin->run_checks();
my ($code, $msg) = $plugin->check_messages(join => ', ');
$plugin->nagios_exit($code, $msg);
sub get_exports_rules
{
my $srv = shift;
my $persistent = shift;
my $res = undef;
$res = $srv->invoke('nfs-exportfs-list-rules', 'persistent', $persistent);
$plugin->die_on_error($res, "Failed to read exports information");
if (! $res->child_get('rules')) {
return ();
}
my %exports = ();
foreach my $rule ($res->child_get('rules')->children_get()) {
my %rule;
my $tmp;
foreach my $info (qw( actual-pathname anon nosuid pathname )) {
$tmp = $rule->child_get_string($info);
if (defined($tmp)) {
$rule{$info} = $tmp;
}
}
foreach my $info (qw( read-only read-write root )) {
my %info = ();
if (! $rule->child_get($info)) {
next;
}
foreach my $host_info ($rule->child_get($info)->children_get()) {
my $host;
my $all_hosts = $host_info->child_get_string('all-hosts');
my $negate = $host_info->child_get_string('negate');
$all_hosts ||= "false";
$negate ||= "false";
if ($all_hosts eq 'true') {
$host = '*';
}
else {
$host = $host_info->child_get_string('name');
}
if ($negate eq 'true') {
$info{$host} = 1;
}
else {
$info{$host} = 0;
}
}
$rule{$info} = \%info;
}
if ($rule->child_get('sec-flavor')) {
my %sec_flavors = map {
$_->child_get_string('flavor') => 1
} $rule->child_get('sec-flavor')->children_get();
$rule{'sec-flavor'} = \%sec_flavors;
}
$exports{$rule{'pathname'}} = \%rule;
}
return %exports;
}
sub check_exportfs_consistent
{
my $plugin = shift;
my $srv = shift;
my @targets = @_;
my %exports = get_exports_rules($srv, 'true');
my %memory = get_exports_rules($srv, 'false');
# diff export rules
foreach my $path (keys %memory) {
if (! defined($exports{$path})) {
$plugin->add_message(CRITICAL,
"$path not exported in /etc/exports");
next;
}
my %export = %{$exports{$path}};
my %mem = %{$memory{$path}};
foreach my $info (qw( actual-pathname anon nosuid pathname )) {
my $e = $export{$info};
my $m = $mem{$info};
if ((! defined($e)) && (! defined($m))) {
next;
}
$e ||= "<empty>";
$m ||= "<empty>";
if ($e ne $m) {
$plugin->add_message(CRITICAL, "$path: $info differ "
. "(exports: $e, exportfs: $m)");
}
}
foreach my $info (qw( read-only read-write root )) {
my $e = $export{$info};
my $m = $mem{$info};
if ((! defined($e)) && (! defined($m))) {
next;
}
foreach my $host (keys %$m) {
if (! defined($e->{$host})) {
$plugin->add_message(CRITICAL, "$path: "
. "$host does not have $info access in /etc/exports");
next;
}
if ($m->{$host} != $e->{$host}) {
$plugin->add_message(CRITICAL, "$path: "
. "$host is negated in "
. ($m->{$host} ? "/etc/exports" : "exportfs info"));
}
}
foreach my $host (keys %$e) {
if (! defined($m->{$host})) {
$plugin->add_message(CRITICAL, "$path: "
. "$host does not have $info access in exportfs info");
}
}
}
my $e = $export{'sec-flavor'};
my $m = $mem{'sec-flavor'};
if (! ((! defined($e)) && (! defined($m)))) {
$e ||= {};
$m ||= {};
foreach my $flavor (keys %$m) {
if (! defined($e->{$flavor})) {
$plugin->add_message(CRITICAL, "$path: "
. "security flavor $flavor is not specified "
. "in /etc/exports");
}
}
foreach my $flavor (keys %$e) {
if (! defined($m->{$flavor})) {
$plugin->add_message(CRITICAL, "$path: "
. "security flavor $flavor is not specified "
. "in exportfs info");
}
}
}
}
foreach my $path (keys %exports) {
if (! defined($memory{$path})) {
$plugin->add_message(CRITICAL,
"$path not exported (according to 'exportfs')");
}
}
}

View file

@ -1,540 +0,0 @@
#############################################################################
# (c) 2011-2012 Sebastian "tokkee" Harl <sh@teamix.net> #
# and team(ix) GmbH, Nuernberg, Germany #
# #
# This file is part of "team(ix) Monitoring Plugins" #
# URL: http://oss.teamix.org/projects/monitoringplugins/ #
# #
# All rights reserved. #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions #
# are met: #
# 1. Redistributions of source code must retain the above copyright #
# notice, this list of conditions and the following disclaimer. #
# 2. Redistributions in binary form must reproduce the above copyright #
# notice, this list of conditions and the following disclaimer in the #
# documentation and/or other materials provided with the distribution. #
# 3. The name of the copyright owner may not be used to endorse or #
# promote products derived from this software without specific prior #
# written permission. #
# #
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR #
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE #
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, #
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES #
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR #
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) #
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, #
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING #
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE #
# POSSIBILITY OF SUCH DAMAGE. #
#############################################################################
package Nagios::Plugin::JUNOS;
use Carp;
use Data::Dumper;
use POSIX qw( :termios_h );
use Nagios::Plugin;
use JUNOS::Device;
use Nagios::Plugin::Functions qw( %ERRORS %STATUS_TEXT @STATUS_CODES );
# re-export Nagios::Plugin's (default) exports
use Exporter;
our @ISA = qw( Nagios::Plugin Exporter );
our @EXPORT = (@STATUS_CODES);
our @EXPORT_OK = qw( %ERRORS %STATUS_TEXT );
sub new
{
my $class = shift;
my %args = @_;
my $self = Nagios::Plugin->new(%args);
$self->{'conf'} = { verbose => 0 };
$self->{'cl_args'} = [];
$self->{'junos'} = undef;
return bless($self, $class);
}
sub add_arg
{
my $self = shift;
my $arg = shift;
my $spec = $arg->{'spec'};
my $help;
push @{$self->{'cl_args'}}, $arg;
if (defined $arg->{'usage'}) {
$help = $arg->{'usage'};
}
else {
$help = $arg->{'help'};
}
if (defined $arg->{'desc'}) {
my @desc;
if (ref($arg->{'desc'})) {
@desc = @{$arg->{'desc'}};
}
else {
@desc = ( $arg->{'desc'} );
}
foreach my $d (@desc) {
$help .= "\n $d";
}
if (defined $arg->{'default'}) {
$help .= " (default: $arg->{'default'})";
}
}
elsif (defined $arg->{'default'}) {
$help .= "\n (default: $arg->{'default'})";
}
$self->SUPER::add_arg(
spec => $spec,
help => $help,
);
}
sub add_common_args
{
my $self = shift;
my @args = (
{
spec => 'host|H=s',
usage => '-H, --host=HOSTNAME',
desc => 'Hostname/IP of Juniper box to connect to',
default => 'localhost',
},
{
spec => 'port|p=i',
usage => '-p, --port=PORT',
desc => 'Port to connect to',
default => 22,
},
{
spec => 'user|U=s',
usage => '-U, --user=USERNAME',
desc => 'Username to log into box as',
default => 'root',
},
{
spec => 'password|P=s',
usage => '-P, --password=PASSWORD',
desc => 'Password for login username',
default => '<prompt>',
},
);
foreach my $arg (@args) {
$self->add_arg($arg);
}
}
sub add_check_impl
{
my $self = shift;
my $name = shift;
my $sub = shift;
if ((! $name) || (! $sub) || (ref($sub) ne "CODE")) {
carp "Invalid check specification: $name -> $sub";
return;
}
if (! defined($self->{'check_impls'})) {
$self->{'check_impls'} = {};
}
$self->{'check_impls'}->{$name} = $sub;
}
sub get_check_impl
{
my $self = shift;
my $name = shift;
if (! defined($self->{'check_impls'}->{$name})) {
return;
}
return $self->{'check_impls'}->{$name};
}
sub is_valid_check
{
my $self = shift;
my $name = shift;
if (defined $self->{'check_impls'}->{$name}) {
return 1;
}
return;
}
sub set_default_check
{
my $self = shift;
my $def = shift;
if (! $self->is_valid_check($def)) {
carp "set_default_check: Check '$def' does not exist";
return;
}
$self->{'default_check'} = $def;
}
sub configure
{
my $self = shift;
# Predefined arguments (by Nagios::Plugin)
my @predefined_args = qw(
usage
help
version
extra-opts
timeout
verbose
);
$self->getopts;
# Initialize this first, so it may be used right away.
$self->{'conf'}->{'verbose'} = $self->opts->verbose;
foreach my $arg (@{$self->{'cl_args'}}) {
my @c = $self->_get_conf($arg);
$self->{'conf'}->{$c[0]} = $c[1];
}
foreach my $arg (@predefined_args) {
$self->{'conf'}->{$arg} = $self->opts->$arg;
}
}
sub _get_conf
{
my $self = shift;
my $arg = shift;
my ($name, undef) = split(m/\|/, $arg->{'spec'});
my $value = $self->opts->$name || $arg->{'default'};
if ($name eq 'password') {
$self->verbose(3, "conf: password => "
. (($value eq '<prompt>') ? '<prompt>' : '<hidden>'));
}
else {
$self->verbose(3, "conf: $name => $value");
}
return ($name => $value);
}
sub _add_single_check
{
my $self = shift;
my @check = split(m/,/, shift);
my %c = ();
if (! $self->is_valid_check($check[0])) {
return "ERROR: invalid check '$check[0]'";
}
$c{'name'} = $check[0];
$c{'target'} = undef;
if (defined($check[1])) {
my @tmp = split(m/(\+|\~)/, $check[1]);
$c{'target'} = [];
$c{'exclude'} = [];
for (my $i = 0; $i < scalar(@tmp); ++$i) {
my $t = $tmp[$i];
if ((($t ne "+") && ($t ne "~")) || ($i == $#tmp)) {
push @{$c{'target'}}, $t;
next;
}
++$i;
if ($t eq "+") {
push @{$c{'target'}}, $tmp[$i];
}
else {
push @{$c{'exclude'}}, $tmp[$i];
}
}
}
$c{'warning'} = $check[2];
$c{'critical'} = $check[3];
# check for valid thresholds
# set_threshold() will die if any threshold is not valid
$self->set_thresholds(
warning => $c{'warning'},
critical => $c{'critical'},
) || $self->die("ERROR: Invalid thresholds: "
. "warning => $c{'warning'}, critical => $c{'critical'}");
push @{$self->{'conf'}->{'checks'}}, \%c;
}
sub set_checks
{
my $self = shift;
my @checks = @_;
my $err_str = "ERROR:";
if (! defined($self->{'conf'}->{'timeout'})) {
croak "No timeout set -- did you call configure()?";
}
if (scalar(@checks) == 0) {
if ($self->{'default_check'}) {
$self->{'conf'}->{'checks'}->[0] = {
name => $self->{'default_check'},
target => [],
exclude => [],
warning => undef,
critical => undef,
};
}
return 1;
}
$self->{'conf'}->{'checks'} = [];
foreach my $check (@checks) {
my $e;
$e = $self->_add_single_check($check);
if ($e =~ m/^ERROR: (.*)$/) {
$err_str .= " $1,";
}
}
if ($err_str ne "ERROR:") {
$err_str =~ s/,$//;
$self->die($err_str);
}
}
sub get_checks
{
my $self = shift;
return @{$self->{'conf'}->{'checks'}};
}
sub connect
{
my $self = shift;
my $host = $self->{'conf'}->{'host'};
my $user = $self->{'conf'}->{'user'};
if ((! $host) || (! $user)) {
croak "Host and/or user not set -- did you call configure()?";
}
if (! $self->opts->password) {
my $term = POSIX::Termios->new();
my $lflag;
print "Password: ";
$term->getattr(fileno(STDIN));
$lflag = $term->getlflag;
$term->setlflag($lflag & ~POSIX::ECHO);
$term->setattr(fileno(STDIN), TCSANOW);
$self->{'conf'}->{'password'} = <STDIN>;
chomp($self->{'conf'}->{'password'});
$term->setlflag($lflag | POSIX::ECHO);
$term->setattr(fileno(STDIN), TCSAFLUSH);
print "\n";
}
$self->verbose(1, "Connecting to host $host as user $user.");
$junos = JUNOS::Device->new(
hostname => $host,
login => $user,
password => $self->{'conf'}->{'password'},
access => 'ssh',
'ssh-compress' => 0);
if (! ref $junos) {
$self->die("ERROR: failed to connect to $host!");
}
$self->{'junos'} = $junos;
return $junos;
}
sub run_checks
{
my $self = shift;
foreach my $check ($self->get_checks()) {
my $targets = [];
my $exclude = [];
if (defined $check->{'target'}) {
$targets = $check->{'target'};
}
if (defined $check->{'exclude'}) {
$exclude = $check->{'exclude'};
}
$self->set_thresholds(
warning => $check->{'warning'},
critical => $check->{'critical'},
);
my $sub = $self->get_check_impl($check->{'name'});
$sub->($self, $self->{'junos'}, $targets, $exclude);
}
}
sub send_query
{
my $self = shift;
my $query = shift;
my $queryargs = shift || {};
my $res;
my $err;
$self->verbose(3, "Sending query '$query' "
. join(", ", map { "$_ => $queryargs->{$_}" } keys %$queryargs)
. " to router.");
if (scalar(keys %$queryargs)) {
$res = $self->{'junos'}->$query(%$queryargs);
} else {
eval {
$res = $self->{'junos'}->$query();
};
if ($@) {
$res = $self->{'junos'}->command($query);
}
}
$self->verbose(5, "Got response: " . Dumper(\$res));
if (! ref $res) {
return "ERROR: Failed to execute query '$query'";
}
$err = $res->getFirstError();
if ($err) {
return "ERROR: " . $err->{message};
}
return $res;
}
sub get_query_object
{
my $self = shift;
my $res = shift;
my $spec = shift;
if (! $res) {
return;
}
if (! $spec) {
return $res;
}
if (! ref($spec)) {
$spec = [ $spec ];
}
my $iter = $res;
for (my $i = 0; $i < scalar(@$spec) - 1; ++$i) {
my $tmp = $iter->getElementsByTagName($spec->[$i]);
if ((! $tmp) || (! $tmp->item(0))) {
return;
}
$iter = $tmp->item(0);
}
if (wantarray) {
my @ret = $iter->getElementsByTagName($spec->[scalar(@$spec) - 1]);
return @ret;
}
else {
my $ret = $iter->getElementsByTagName($spec->[scalar(@$spec) - 1]);
if ((! $ret) || (! $ret->item(0))) {
return;
}
return $ret->item(0);
}
}
sub get_query_object_value
{
my $self = shift;
my $res = $self->get_query_object(@_);
if (! $res) {
return;
}
if (ref($res) eq "XML::DOM::NodeList") {
$res = $res->item(0);
}
return $res->getFirstChild->getNodeValue;
}
sub nagios_exit
{
my $self = shift;
if ($self->{'junos'}) {
$self->{'junos'}->disconnect();
}
$self->SUPER::nagios_exit(@_);
}
sub verbose
{
my $self = shift;
my $level = shift;
my @msgs = @_;
if ($level > $self->{'conf'}->{'verbose'}) {
return;
}
foreach my $msg (@msgs) {
print "V$level: $msg\n";
}
}
return 1;

View file

@ -1,453 +0,0 @@
#############################################################################
# (c) 2011-2012 Sebastian "tokkee" Harl <sh@teamix.net> #
# and team(ix) GmbH, Nuernberg, Germany #
# #
# This file is part of "team(ix) Monitoring Plugins" #
# URL: http://oss.teamix.org/projects/monitoringplugins/ #
# #
# All rights reserved. #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions #
# are met: #
# 1. Redistributions of source code must retain the above copyright #
# notice, this list of conditions and the following disclaimer. #
# 2. Redistributions in binary form must reproduce the above copyright #
# notice, this list of conditions and the following disclaimer in the #
# documentation and/or other materials provided with the distribution. #
# 3. The name of the copyright owner may not be used to endorse or #
# promote products derived from this software without specific prior #
# written permission. #
# #
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR #
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE #
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, #
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES #
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR #
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) #
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, #
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING #
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE #
# POSSIBILITY OF SUCH DAMAGE. #
#############################################################################
package Nagios::Plugin::NetApp;
use Carp;
use POSIX qw( :termios_h );
use Nagios::Plugin;
use NaServer;
use Nagios::Plugin::Functions qw( %ERRORS %STATUS_TEXT @STATUS_CODES );
# re-export Nagios::Plugin's (default) exports
use Exporter;
our @ISA = qw( Nagios::Plugin Exporter );
our @EXPORT = (@STATUS_CODES);
our @EXPORT_OK = qw( %ERRORS %STATUS_TEXT );
sub new
{
my $class = shift;
my %args = @_;
my $self = Nagios::Plugin->new(%args);
$self->{'conf'} = { verbose => 0 };
$self->{'cl_args'} = [];
$self->{'srv'} = undef;
return bless($self, $class);
}
sub add_arg
{
my $self = shift;
my $arg = shift;
my $spec = $arg->{'spec'};
my $help;
push @{$self->{'cl_args'}}, $arg;
if (defined $arg->{'usage'}) {
$help = $arg->{'usage'};
}
else {
$help = $arg->{'help'};
}
if (defined $arg->{'desc'}) {
my @desc;
if (ref($arg->{'desc'})) {
@desc = @{$arg->{'desc'}};
}
else {
@desc = ( $arg->{'desc'} );
}
foreach my $d (@desc) {
$help .= "\n $d";
}
if (defined $arg->{'default'}) {
$help .= " (default: $arg->{'default'})";
}
}
elsif (defined $arg->{'default'}) {
$help .= "\n (default: $arg->{'default'})";
}
$self->SUPER::add_arg(
spec => $spec,
help => $help,
);
}
sub add_common_args
{
my $self = shift;
my @args = (
{
spec => 'host|H=s',
usage => '-H, --host=HOSTNAME',
desc => 'Hostname/IP of NetApp filer to connect to',
default => 'localhost',
},
{
spec => 'port|p=i',
usage => '-p, --port=PORT',
desc => 'Port to connect to',
},
{
spec => 'user|U=s',
usage => '-U, --user=USERNAME',
desc => 'Username to log into box as',
default => 'root',
},
{
spec => 'password|P=s',
usage => '-P, --password=PASSWORD',
desc => 'Password for login username',
default => '<prompt>',
},
{
spec => 'transport|t=s',
usage => '-t, --transport=TRANSPORT',
desc => 'Transport for the connection',
default => 'HTTP',
},
);
foreach my $arg (@args) {
$self->add_arg($arg);
}
}
sub add_check_impl
{
my $self = shift;
my $name = shift;
my $sub = shift;
if ((! $name) || (! $sub) || (ref($sub) ne "CODE")) {
carp "Invalid check specification: $name -> $sub";
return;
}
if (! defined($self->{'check_impls'})) {
$self->{'check_impls'} = {};
}
$self->{'check_impls'}->{$name} = $sub;
}
sub get_check_impl
{
my $self = shift;
my $name = shift;
if (! defined($self->{'check_impls'}->{$name})) {
return;
}
return $self->{'check_impls'}->{$name};
}
sub is_valid_check
{
my $self = shift;
my $name = shift;
if (defined $self->{'check_impls'}->{$name}) {
return 1;
}
return;
}
sub set_default_check
{
my $self = shift;
my $def = shift;
if (! $self->is_valid_check($def)) {
carp "set_default_check: Check '$def' does not exist";
return;
}
$self->{'default_check'} = $def;
}
sub configure
{
my $self = shift;
# Predefined arguments (by Nagios::Plugin)
my @predefined_args = qw(
usage
help
version
extra-opts
timeout
verbose
);
$self->getopts;
# Initialize this first, so it may be used right away.
$self->{'conf'}->{'verbose'} = $self->opts->verbose;
foreach my $arg (@{$self->{'cl_args'}}) {
my @c = $self->_get_conf($arg);
$self->{'conf'}->{$c[0]} = $c[1];
}
foreach my $arg (@predefined_args) {
$self->{'conf'}->{$arg} = $self->opts->$arg;
}
}
sub _get_conf
{
my $self = shift;
my $arg = shift;
my ($name, undef) = split(m/\|/, $arg->{'spec'});
my $value = $self->opts->$name || $arg->{'default'};
if ($name eq 'password') {
$self->verbose(3, "conf: password => "
. (($value eq '<prompt>') ? '<prompt>' : '<hidden>'));
}
else {
$self->verbose(3, "conf: $name => $value");
}
return ($name => $value);
}
sub _add_single_check
{
my $self = shift;
my @check = split(m/,/, shift);
my %c = ();
if (! $self->is_valid_check($check[0])) {
return "ERROR: invalid check '$check[0]'";
}
$c{'name'} = $check[0];
$c{'target'} = undef;
if (defined($check[1])) {
$c{'target'} = [ split(m/\+/, $check[1]) ];
}
$c{'warning'} = $check[2];
$c{'critical'} = $check[3];
# check for valid thresholds
# set_threshold() will die if any threshold is not valid
$self->set_thresholds(
warning => $c{'warning'},
critical => $c{'critical'},
) || $self->die("ERROR: Invalid thresholds: "
. "warning => $c{'warning'}, critical => $c{'critical'}");
push @{$self->{'conf'}->{'checks'}}, \%c;
}
sub set_checks
{
my $self = shift;
my @checks = @_;
my $err_str = "ERROR:";
if (! defined($self->{'conf'}->{'timeout'})) {
croak "No timeout set -- did you call configure()?";
}
if (scalar(@checks) == 0) {
if ($self->{'default_check'}) {
$self->{'conf'}->{'checks'}->[0] = {
name => $self->{'default_check'},
target => [],
warning => undef,
critical => undef,
};
}
return 1;
}
$self->{'conf'}->{'checks'} = [];
foreach my $check (@checks) {
my $e;
$e = $self->_add_single_check($check);
if ($e =~ m/^ERROR: (.*)$/) {
$err_str .= " $1,";
}
}
if ($err_str ne "ERROR:") {
$err_str =~ s/,$//;
$self->die($err_str);
}
}
sub get_checks
{
my $self = shift;
return @{$self->{'conf'}->{'checks'}};
}
sub connect
{
my $self = shift;
my $host = $self->{'conf'}->{'host'};
my $user = $self->{'conf'}->{'user'};
my $srv;
if ((! $host) || (! $user)) {
croak "Host and/or user not set -- did you call configure()?";
}
if (! $self->opts->password) {
my $term = POSIX::Termios->new();
my $lflag;
print "Password: ";
$term->getattr(fileno(STDIN));
$lflag = $term->getlflag;
$term->setlflag($lflag & ~POSIX::ECHO);
$term->setattr(fileno(STDIN), TCSANOW);
$self->{'conf'}->{'password'} = <STDIN>;
chomp($self->{'conf'}->{'password'});
$term->setlflag($lflag | POSIX::ECHO);
$term->setattr(fileno(STDIN), TCSAFLUSH);
print "\n";
}
$self->verbose(1, "Connecting to host $host as user $user.");
$srv = new NaServer($host, 1, 7);
if (! $srv) {
$self->die("ERROR: failed to connect to $host!");
}
$srv->set_admin_user($user, $self->{'conf'}->{'password'});
$srv->set_transport_type($self->{'conf'}->{'transport'});
if ($self->{'conf'}->{'port'}) {
$srv->set_port($self->{'conf'}->{'port'});
}
$srv->set_timeout($self->{'conf'}->{'timeout'});
$self->{'srv'} = $srv;
return $srv;
}
sub run_checks
{
my $self = shift;
foreach my $check ($self->get_checks()) {
my @targets = ();
if (defined $check->{'target'}) {
@targets = @{$check->{'target'}};
}
$self->set_thresholds(
warning => $check->{'warning'},
critical => $check->{'critical'},
);
my $sub = $self->get_check_impl($check->{'name'});
$sub->($self, $self->{'srv'}, @targets);
}
}
sub get_error
{
my $self = shift;
my $res = shift;
my $msg = shift;
if (! defined($res)) {
return "$msg: Unknown error";
}
elsif ((ref($res) eq "NaElement") && (($res->results_errno != 0)
|| ($res->results_status() eq "failed"))) {
return "$msg: " . $res->results_reason();
}
return;
}
sub die_on_error
{
my $self = shift;
if ($self->get_error(@_)) {
$self->die($self->get_error(@_));
}
return 1;
}
sub nagios_exit
{
my $self = shift;
if ($self->{'srv'}) {
$self->{'srv'} = undef;
}
$self->SUPER::nagios_exit(@_);
}
sub verbose
{
my $self = shift;
my $level = shift;
my @msgs = @_;
if ($level > $self->{'conf'}->{'verbose'}) {
return;
}
foreach my $msg (@msgs) {
print "V$level: $msg\n";
}
}
return 1;

View file

@ -1,79 +0,0 @@
#! /usr/bin/perl
#####################################################################
# (c) 2012 Sebastian "tokkee" Harl <sh@teamix.net> #
# and team(ix) GmbH, Nuernberg, Germany #
# #
# This file is part of "team(ix) Monitoring Plugins" #
# URL: http://oss.teamix.org/projects/monitoringplugins/ #
# #
# This file is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published #
# by the Free Software Foundation, either version 2 of the License, #
# or (at your option) any later version. #
# #
# This file is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this file. If not, see <http://www.gnu.org/licenses/>. #
#####################################################################
use strict;
use warnings;
my $p_script = shift;
my @p_args = @ARGV;
if (! $p_script) {
exit_usage(1);
}
my $p_stdout;
my $p_pid = open($p_stdout, '-|', "$p_script @p_args 2>&1");
if (! defined($p_pid)) {
print "CRITICAL: Failed to execute plugin ($p_script): $!\n";
print "Commandline: $p_script @p_args\n";
exit 2;
}
my @p_output = <$p_stdout>;
if (waitpid($p_pid, 0) != $p_pid) {
print "UNKNOWN: Lost track of plugin process\n";
exit 3;
}
my $p_rc = $?;
my $p_sig = $p_rc & 127;
my $p_cd = $p_rc & 128; # core dumped?
$p_rc >>= 8;
close $p_stdout;
if ($p_sig || $p_cd) {
print "CRITICAL: Plugin died with signal $p_sig (exit code: $p_rc)"
. ($p_cd ? " (core dumped)" : "") . "\n";
$p_rc = 2;
}
if ($p_rc == 255) {
print "CRITICAL: Plugin died with status 255 "
. "(see details for more info)\n";
print "Commandline: $p_script @p_args\n";
}
my $p_output = join('', @p_output);
print $p_output;
if (($p_rc < 0) || ($p_rc > 3)) {
$p_rc = 3;
}
exit $p_rc;
sub exit_usage {
my $status = shift || 0;
print STDERR "Usage: $0 <plugin> [<args>]\n";
exit $status;
}

View file

@ -1,239 +0,0 @@
#! /usr/bin/perl -w
#############################################################################
# (c) 2001, 2003 Juniper Networks, Inc. #
# (c) 2011 Sebastian "tokkee" Harl <sh@teamix.net> #
# and team(ix) GmbH, Nuernberg, Germany #
# #
# This file is part of "team(ix) Monitoring Plugins" #
# URL: http://oss.teamix.org/projects/monitoringplugins/ #
# It is based on the example diagnose_bgp.pl script of the #
# JUNOScript distribution. #
# #
# All rights reserved. #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions #
# are met: #
# 1. Redistributions of source code must retain the above copyright #
# notice, this list of conditions and the following disclaimer. #
# 2. Redistributions in binary form must reproduce the above copyright #
# notice, this list of conditions and the following disclaimer in the #
# documentation and/or other materials provided with the distribution. #
# 3. The name of the copyright owner may not be used to endorse or #
# promote products derived from this software without specific prior #
# written permission. #
# #
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR #
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE #
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, #
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES #
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR #
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) #
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, #
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING #
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE #
# POSSIBILITY OF SUCH DAMAGE. #
#############################################################################
use strict;
use warnings;
use JUNOS::Device;
use JUNOS::Trace;
use Getopt::Std;
use Term::ReadKey;
use File::Basename;
use Data::Dumper;
my $jnx;
# send a query
sub send_query
{
my $device = shift;
my $query = shift;
my $href_queryargs = shift;
my $res;
unless ( ref $href_queryargs ) {
eval {
$res = $device->$query();
};
if ($@) {
$res = $device->command($query);
}
} else {
my %queryargs = %$href_queryargs;
print "$_ => $queryargs{$_}\n" foreach (keys %queryargs);
$res = $device->$query(%queryargs);
}
unless ( ref $res ) {
print STDERR "ERROR: Failed to execute query '$query'\n";
return 0;
}
unless (ref $res) {
print STDERR "ERROR: failed to execute command $query\n";
return undef;
}
my $err = $res->getFirstError();
if ($err) {
print STDERR "ERROR: ", $err->{message}, "\n";
return 0;
}
return $res;
}
# get object identified by the specified spec
sub get_object_by_spec
{
my $res = shift;
my $spec = shift;
my $iter = $res;
for (my $i = 0; $i < scalar(@$spec) - 1; ++$i) {
my $tmp = $iter->getElementsByTagName($spec->[$i]);
if ((! $tmp) || (! $tmp->item(0))) {
return;
}
$iter = $tmp->item(0);
}
if (wantarray) {
my @ret = $iter->getElementsByTagName($spec->[scalar(@$spec) - 1]);
return @ret;
}
else {
my $ret = $iter->getElementsByTagName($spec->[scalar(@$spec) - 1]);
if ((! $ret) || (! $ret->item(0))) {
return;
}
return $ret->item(0);
}
}
# print the usage of this script
sub output_usage
{
my $usage = "Usage: $0 [options] <target> <query> [<arg1>=<value1> [...]]
Where:
<target> The hostname of the target router.
<query> The query to send to the target router.
Options:
-l <login> A login name accepted by the target router.
-p <password> The password for the login name.
-m <access> Access method. It can be clear-text, ssl, ssh or telnet. Default: telnet.
-s <spec> Specify a value to extract from the output.
-o <file> Output file. Default: dump.xml.
-d Turn on debug, full blast.\n\n";
die $usage;
}
my %opt;
getopts('l:p:dm:x:o:s:h', \%opt) || output_usage();
output_usage() if $opt{h};
# Check whether trace should be turned on
JUNOS::Trace::init(1) if $opt{d};
my $hostname = shift || output_usage();
my $query = shift || output_usage();
my %args = map { split m/=/, $_ } @ARGV;
if ($opt{d}) {
print "Args:\n";
foreach my $key (keys %args) {
print "\t$key => $args{$key}\n";
}
}
# Retrieve the access method, can only be telnet or ssh.
my $access = $opt{m} || "telnet";
use constant VALID_ACCESSES => "telnet|ssh|clear-text|ssl";
output_usage() unless (VALID_ACCESSES =~ /$access/);
# Check whether login name has been entered. Otherwise prompt for it
my $login = "";
if ($opt{l}) {
$login = $opt{l};
} else {
print "login: ";
$login = ReadLine 0;
chomp $login;
}
# Check whether password has been entered. Otherwise prompt for it
my $password = "";
if ($opt{p}) {
$password = $opt{p};
} else {
print "password: ";
ReadMode 'noecho';
$password = ReadLine 0;
chomp $password;
ReadMode 'normal';
print "\n";
}
# Get the name of the output file
my $outfile = $opt{o} || 'dump.xml';
# Retrieve command line arguments
my %deviceinfo = (
access => $access,
login => $login,
password => $password,
hostname => $hostname,
'ssh-compress' => 0,
);
#
# CONNECT TO the JUNOScript server
# Create a device object that contains all necessary information to
# connect to the JUNOScript server at a specific router.
#
$jnx = new JUNOS::Device(%deviceinfo);
unless ( ref $jnx ) {
die "ERROR: $deviceinfo{hostname}: failed to connect.\n";
}
my $spec = $opt{s} || undef;
if ($spec) {
$spec = [ split(",", $spec) ];
}
my $res = send_query($jnx, $query, scalar(keys %args) ? \%args : undef);
while ($res) {
if ($spec) {
$res = get_object_by_spec($res, $spec);
}
if (! $res) {
print "NO OUTPUT!\n";
last;
}
if ($outfile eq "-") {
print STDOUT $res->toString;
}
else {
$res->printToFile($outfile);
}
last;
}
$jnx->request_end_session();
$jnx->disconnect();