monitoring-plugins-sentry3/check_sentry3

775 lines
24 KiB
Perl

#!/usr/bin/perl
#
# check_sentry3 - Nagios(r) network traffic monitor plugin
# Copyright (C) 2012 Peter Harrison / www.linuxhomenetworking.com
#
# This Nagios check monitors Servertech devices that use the Sentry3 MIB.
# It checks the following:
# 1) Environmental temperature (Auto-detects all sensors)
# 2) Environmental humidity (Auto-detects all sensors)
# 3) Input power (Auto-detects all input feeds)
#
# Prerequisite Perl modules:
#
# Net::SNMP
# Nagios::Plugin
#
# Though Net::SNMP may be installable using package systems such as yum or apt,
# Nagios::Plugin may have to be done by hand like this:
#
# $ perl -MCPAN -e 'install Nagios::Plugin'
#
################################################################################
# Modification History
################################################################################
#
# Put first modification description below here:
#
################################################################################
# Legal stuff...
################################################################################
#
# Send us bug reports, questions and comments about this plugin.
# Latest version of this software: http://www.nagiosexchange.org
#
#
# This program 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 program 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 program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307
#
################################################################################
# Let the coding begin ...
################################################################################
use Getopt::Long;
&Getopt::Long::config('bundling');
use strict;
use Nagios::Plugin;
use Net::SNMP;
# Run the program
&main();
exit;
sub main{
my $get_help = 0;
my $get_morehelp = 0;
my %cmd_flags = ();
# SNMP Specific
my %snmp_vars = ();
my %snmp_results = ();
$snmp_vars{port} = 161;
$snmp_vars{version} = 2;
$snmp_vars{community} = "public";
# Define the OIDs we are interested in
my %oids = ();
#
# Important stuff below, do not erase as it is good information:
#
#$oids{temp_value} = "Sentry3-MIB::tempHumidSensorTempValue";
#$oids{humid_value} = "Sentry3-MIB::tempHumidSensorHumidValue";
#$oids{power_value} = "Sentry3-MIB::infeedLoadValue";
#
# I originally used the MIB, but wanted after convertint to Net-SNMP
# I had to use the oids. This is how I got them.
#
# /usr/bin/snmpwalk -v 2c -c public 66.214.208.171 enterprise > file1.txt
# /usr/bin/snmpwalk -v 2c -On -c public 66.214.208.171 enterprise > file2.txt
$oids{temp_value} = ".1.3.6.1.4.1.1718.3.2.5.1.6";
$oids{humid_value} = ".1.3.6.1.4.1.1718.3.2.5.1.10";
$oids{power_value} = ".1.3.6.1.4.1.1718.3.2.2.1.7";
# Verify that we have the correct options listed
GetOptions(
"c|critical-level=s" => \$cmd_flags{crit_level},
"w|warning-level=s" => \$cmd_flags{warn_level},
"d|temperature" => \$cmd_flags{do_temp},
"e|humidity" => \$cmd_flags{do_humid},
"f|power" => \$cmd_flags{do_power},
"b|celcius" => \$cmd_flags{celcius},
"B|fahrenheit" => \$cmd_flags{fahrenheit},
"h|help" => \$get_help,
"m|morehelp" => \$get_morehelp,
"H|hostname=s" => \$snmp_vars{hostname},
"p|port=i" => \$snmp_vars{port},
"C|community=s" => \$snmp_vars{community},
"s|username=s" => \$snmp_vars{username},
"v|version=i" => \$snmp_vars{version},
"T|authpassword=s" => \$snmp_vars{authpassword},
"t|authprotocol=s" => \$snmp_vars{authprotocol},
"X|privpassword=s" => \$snmp_vars{privpassword},
"x|privprotocol=s" => \$snmp_vars{privprotocol}
);
# Test for file validity and Help
if($get_help){&usage();}
if($get_morehelp){&moreusage();}
if(!$snmp_vars{hostname}){&usage();}
# usage notes
if (
( ! defined $cmd_flags{crit_level} ) ||
( ! defined $cmd_flags{warn_level} )
) {&nagios_exit("Critical Level or Warning Level not specified on the command line","UNKNOWN");}
# usage notes (Specific to temperature)
if (
(( ! defined $cmd_flags{celcius} ) &&
( ! defined $cmd_flags{fahrenheit} )) &&
defined $cmd_flags{do_temp}
) {&nagios_exit("Temperature mode defined, but don't know whether to use Celcius or Fahrenheit mode","UNKNOWN");}
# Define what to do
if(defined $cmd_flags{do_temp}){
$cmd_flags{do_power} = 0;
$cmd_flags{do_humid} = 0;
}
elsif(defined $cmd_flags{do_humid}){
$cmd_flags{do_temp} = 0;
$cmd_flags{do_power} = 0;
}
elsif(defined $cmd_flags{do_power}){
$cmd_flags{do_temp} = 0;
$cmd_flags{do_humid} = 0;
}
&nagios_report(\%cmd_flags,\%snmp_vars,\%oids);
}
sub nagios_report {
# Passing multiple arrays into subroutine
my %cmd_flags = %{$_[0]};
my %snmp_vars = %{$_[1]};
my %oids = %{$_[2]};
my %poll_results = ();
my @nagios_value = "";
my $np = 0;
my $np_threshold = 0;
my $temp_uom = "";
my $count = -1;
my $message = "";
# Get all the OID values
my ($poll_pointer) = &get_data(\%cmd_flags,\%snmp_vars,\%oids);
# Get the results
%poll_results = %$poll_pointer;
# Create the object, we are going to be adding data to it multiple times
if ($cmd_flags{do_temp}){
$np = Nagios::Plugin->new(shortname => "SERVERTECH_TEMPERATURE");
}
elsif ($cmd_flags{do_humid}){
$np = Nagios::Plugin->new(shortname => "SERVERTECH_HUMIDITY");
}
elsif ($cmd_flags{do_power}){
$np = Nagios::Plugin->new(shortname => "SERVERTECH_AMPS");
}
foreach my $key (sort keys(%poll_results)){
# Increment count
$count +=1;
# Define the values we are going to test against
$nagios_value[$count] = sprintf("%.2f",$poll_results{$key});
# Process the value
if ($cmd_flags{do_temp}){
# Set up the thresholds we are interested in
$np_threshold = $np->set_thresholds(
warning => $cmd_flags{warn_level} ,
critical => $cmd_flags{crit_level} );
# Determine the Unit of Measure
if ($cmd_flags{celcius}){$temp_uom = "C";}else{$temp_uom = "F";}
# Define the performance data
$np->add_perfdata(
label => "Temperature" . sprintf("%d",$count + 1),
value => $nagios_value[$count],
threshold => $np_threshold,
uom => $temp_uom
);
# Update $message
$message .= "Temperature" . sprintf("%d @ ", $count + 1) . sprintf("%.2f",$nagios_value[$count]) . $temp_uom . ", ";
}
elsif ($cmd_flags{do_humid}){
# Set up the thresholds we are interested in
$np_threshold = $np->set_thresholds(
warning => $cmd_flags{warn_level} ,
critical => $cmd_flags{crit_level} );
# Define the performance data
$np->add_perfdata(
label => "Humidity" . sprintf("%d",$count + 1),
value => $nagios_value[$count],
threshold => $np_threshold,
uom => "%"
);
# Update $message
$message .= "Humidity" . sprintf("%d @ ", $count + 1) . sprintf("%.2f",$nagios_value[$count]) . "%, ";
}
elsif ($cmd_flags{do_power}){
# Set up the thresholds we are interested in
$np_threshold = $np->set_thresholds(
warning => $cmd_flags{warn_level} ,
critical => $cmd_flags{crit_level} );
# Define the performance data
$np->add_perfdata(
label => "Input" . sprintf("%d",$count + 1),
value => $nagios_value[$count],
threshold => $np_threshold,
uom => "A"
);
# Update $message
$message .= "Input" . sprintf("%d @ ", $count + 1) . sprintf("%.2f",$nagios_value[$count]) . "A, ";
}
}
# Remove trailing comma from $message
$message =~ s/\,+\s+$//g;
# Process and exit
$np->nagios_exit(
return_code => $np->check_threshold(check => \@nagios_value), message => $message
);
}
sub get_data {
# Passing multiple arrays into subroutine
my %cmd_flags = %{$_[0]};
my %snmp_vars = %{$_[1]};
my %oids = %{$_[2]};
# Initialize variables
my %walk_results = ();
my $walk_pointer = undef;
my $session = undef;
my $oid_to_walk = ""; # Used for getting individual sensor statuses
my $session;
my $error;
# Poll specific OID for a value
if($cmd_flags{do_temp}){
$oid_to_walk = $oids{temp_value};
}
elsif ($cmd_flags{do_humid}){
$oid_to_walk = $oids{humid_value};
}
elsif ($cmd_flags{do_power}){
$oid_to_walk = $oids{power_value};
}
################################################################
# Do SNMP bulk query and put results in %walk_results array
# after running the analyse_walk routine
# Get SNMP Session pointer
$session = &get_snmp_session_blocking(\%snmp_vars);
# Define what to do when the query is done
my $result = $session->get_bulk_request(
-varbindlist => [ $oid_to_walk ],
-callback => [ \&analyse_walk, \%walk_results, $oid_to_walk ],
-maxrepetitions => 10,
);
# If we get no result then exit and DIE!
if (!defined $result) {
&nagios_exit($session->error(),"UNKNOWN");
}
# Now initiate the SNMP message exchange.
snmp_dispatcher();
$session->close();
################################################################
# Go through the results in sorted order and adjust values
foreach my $key (sort keys(%walk_results)){
# Temperatures are recorded in tenths of a degree
if($cmd_flags{do_temp}){
$walk_results{$key} = $walk_results{$key}/10;
}
# Current is recorded in hundredths of an amp
elsif($cmd_flags{do_power}){
$walk_results{$key} = $walk_results{$key}/100;
}
}
# Return all the results
return(\%walk_results);
}
sub analyse_walk{
# Purpose: Analyses the results of the walk
my ($session, $table, $oid_to_walk) = @_;
# Define variables used in this routine
my $next = undef;
# Define a pointer to the get hash reference for the VarBindList values (snmpget results)
my $list = $session->var_bind_list();
# If there is an error say so! Then DIE!
if (!defined $session) {
&nagios_exit($session->error(),"UNKNOWN");
}
# Get the array of the ObjectNames (OIDs) in the VarBindList
my @names = $session->var_bind_names();
# Loop through each of the OIDs in the response and assign
# the key/value pairs to the reference that was passed with
# the callback. Make sure that we are still in the table
# before assigning the key/values.
foreach $next (@names) {
if (!is_child_oid($oid_to_walk, $next)) {
return; # Table is done.
}
$table->{$next} = $list->{$next};
}
# Table is not done, send another request, starting at the last
# OBJECT IDENTIFIER in the response. No need to include the
# calback argument, the same callback that was specified for the
# original request will be used.
my $result = $session->get_bulk_request(
-varbindlist => [ $next ],
-maxrepetitions => 10,
);
# If we get no result then exit and DIE!
if (!defined $result) {
&nagios_exit($session->error(),"UNKNOWN");
}
return;
}
sub is_child_oid{
my ($oid_tree,$oid_child) = @_;
my $count = 0;
my $return_ok = 1;
my @tree_array = split('\.',$oid_tree);
my @child_array = split('\.',$oid_child);
# Compare $oid_tree and $oid_child.
# If any octet in $oid_tree doesn't match the same octet in $oid_child then exit with "0" (Fail)
foreach my $temp (@tree_array){
if ($tree_array[$count] != $child_array[$count]){$return_ok = 0; last;}
$count +=1;
}
return ($return_ok);
}
sub get_snmp_session_blocking {
# Passing multiple arrays into subroutine
my %snmp_vars = %{$_[0]};
# Define the SNMP session variable
my $session;
my $error;
#
# Check for missing options
#
# Check missing host name
if (!$snmp_vars{hostname}){
&nagios_exit("Missing host address!","UNKNOWN");
}
# Make some variables lower case
if ($snmp_vars{privprotocol}){$snmp_vars{privprotocol} = lc($snmp_vars{privprotocol});}
if ($snmp_vars{authprotocol}){$snmp_vars{authprotocol} = lc($snmp_vars{authprotocol});}
# Check SNMP version compatibility (Versions 1 & 2)
if ( $snmp_vars{version} =~ /[12]/ ) {
( $session, $error ) = Net::SNMP->session(
-hostname => $snmp_vars{hostname},
-community => $snmp_vars{community},
-port => $snmp_vars{port},
-nonblocking => 1,
-translate => [-octetstring => 0],
-version => $snmp_vars{version}
);
} # / SNMP version 1 or 2
# Check SNMP version compatibility (version 3)
elsif ( $snmp_vars{version} =~ /3/ ) {
# AuthPriv mode
if($snmp_vars{privpassword}){
($session, $error) = Net::SNMP->session(
-username => $snmp_vars{username},
-authpassword => $snmp_vars{authpassword},
-authprotocol => $snmp_vars{authprotocol},
-privpassword => $snmp_vars{privpassword},
-privprotocol => $snmp_vars{privprotocol},
-hostname => $snmp_vars{hostname},
-port => $snmp_vars{port},
-nonblocking => 1,
-translate => [-octetstring => 0],
-version => $snmp_vars{version}
);
} # /AuthPriv mode
# AuthNoPriv options
else{
# AuthNoPriv mode
if($snmp_vars{authprotocol}){
($session, $error) = Net::SNMP->session(
-username => $snmp_vars{username},
-authpassword => $snmp_vars{authpassword},
-authprotocol => $snmp_vars{authprotocol},
-hostname => $snmp_vars{hostname},
-port => $snmp_vars{port},
-nonblocking => 1,
-translate => [-octetstring => 0],
-version => $snmp_vars{version}
);
} # /AuthNoPriv mode
# noAuthNoPriv mode
else{
($session, $error) = Net::SNMP->session(
-username => $snmp_vars{username},
-authpassword => $snmp_vars{authpassword},
-hostname => $snmp_vars{hostname},
-port => $snmp_vars{port},
-nonblocking => 1,
-translate => [-octetstring => 0],
-version => $snmp_vars{version}
);
} # /noAuthNoPriv mode
} # /AuthNoPriv options
} # /SNMP version 3
# Some other version of SNMP
else {
&nagios_exit("Unknown SNMP v" . $snmp_vars{version},"UNKNOWN");
};
# Things failed, so DIE!
if ( !defined($session) ) {
&nagios_exit($error,"UNKNOWN");
};
# Return the session pointer
return($session);
}
sub nagios_exit {
my ($message, $status) = @_;
$status = uc($status);
$message = $status . ": " . $message;
if ($status eq "UNKNOWN"){
my $np = Nagios::Plugin->new(shortname => "UNKNOWN");
$np->nagios_exit(UNKNOWN, $message);
}
elsif ($status eq "WARNING"){
my $np = Nagios::Plugin->new(shortname => "WARNING");
$np->nagios_exit( WARNING, $message )
}
elsif ($status eq "CRITICAL"){
my $np = Nagios::Plugin->new(shortname => "CRITICAL");
$np->nagios_exit( CRITICAL, $message )
}
}
sub usage {
print STDERR << "EOF";
This program is a Nagios check the monitors servertech devices
using the Sentry3.mib MIB
It checks the following:
1) Environmental temperature (Auto-detects all sensors)
2) Environmental humidity (Auto-detects all sensors)
3) Input power (Auto-detects all input feeds)
Prerequisite Perl modules:
Net::SNMP
Nagios::Plugin
Though Net::SNMP may be installable using package systems such as yum or apt,
Nagios::Plugin may have to be done by hand like this:
# perl -MCPAN -e 'install Nagios::Plugin'
# perl -MCPAN -e 'install Net::SNMP'
usage: $0 [--help]
-h, --help
This help message
-m, --morehelp
Detailed help on how to edit Nagios / Icinga configuration files to get this
check working for you
-H, --hostname STRING or IPADDRESS
Host to query via SNMP
-C, --community STRING
SNMP Community (Default = "public")
-v, --version INTEGER
SNMP version (Default = 2)
-p, --port INTEGER
SNMP UDP port (Default = 161)
-s, --username
Set the securityName used for authenticated SNMPv3 communication.
-T, --authpassword
Set the SNMPv3 authentication pass phrase used for authenticated SNMPv3 communication.
-t, --authprotocol
Set the authentication protocol (MD5 or SHA) used for authenticated SNMPv3
communication.
-X, --privpassword
Set the privacy pass phrase used for encrypted SNMPv3 communication.
-x, --privprotocol
Set the privacy protocol (DES or AES) used for encrypted SNMPv3 communication.
-e, --humidity
Used if you are tracking humidity
-f, --power
Used if you are tracking power
-d, --temperature
Used if you are tracking temperature
-B, --fahrenheit
Used with --temperature
-b, --celcius
Used with --temperature
-c, --critical-level STRING
Critical level to use
-w, --warning-level STRING
Warning level to use
EOF
exit();
}
sub moreusage {
print STDERR << "EOF";
# Without PNP4Nagios ########################################################################
Sample SNMPv2 commands
to add to your Nagios / Icinga command file
#############################################################################################
define command{
command_name check_sentry3_amps
command_line \$USER1\$/check_sentry3 --hostname \$HOSTADDRESS\$ --power --community \$ARG1\$ --warning \$ARG2\$ --critical \$ARG3\$
}
define command{
command_name check_sentry3_temp
command_line \$USER1\$/check_sentry3 --hostname \$HOSTADDRESS\$ --temp --community \$ARG1\$ --warning \$ARG2\$ --critical \$ARG3\$ \$ARG4\$
}
define command{
command_name check_sentry3_humid
command_line \$USER1\$/check_sentry3 --hostname \$HOSTADDRESS\$ --humid --community \$ARG1\$ --warning \$ARG2\$ --critical \$ARG3\$
}
# Without PNP4Nagios ########################################################################
Sample SNMPv2 checks
to add to the Nagios / Icinga file where your checks are located
Note: Servertechs often have multiple sensors of the same type. With this check Nagios /
Icinga will alarm when any of the temperature, power or humidity thresholds is exceeded on
any of the specified type of sensor. This check automatically detects the number of sensors.
#############################################################################################
# Servertech (AMPS)
define service{
use local-service ; Name of service template to use
host_name servertech-cdu
service_description AMPS
check_command check_sentry3_amps!public!16!18
}
# Servertech (HUMIDITY)
define service{
use local-service ; Name of service template to use
host_name servertech-cdu
service_description HUMIDITY
check_command check_sentry3_humid!public!10:!75
}
# Servertech (TEMPERATURE)
define service{
use local-service ; Name of service template to use
host_name servertech-cdu
service_description TEMPERATURE
check_command check_sentry3_temp!public!35:!85!--fahrenheit
}
# With PNP4Nagios ###########################################################################
Sample SNMPv2 commands
to add to your Nagios / Icinga command file
#############################################################################################
define command{
command_name check_sentry3_amps
command_line \$USER1\$/check_sentry3 --hostname \$HOSTADDRESS\$ --power --community \$ARG2\$ --warning \$ARG3\$ --critical \$ARG4\$
}
define command{
command_name check_sentry3_temp
command_line \$USER1\$/check_sentry3 --hostname \$HOSTADDRESS\$ --temp --community \$ARG2\$ --warning \$ARG3\$ --critical \$ARG4\$ \$ARG5\$
}
define command{
command_name check_sentry3_humid
command_line \$USER1\$/check_sentry3 --hostname \$HOSTADDRESS\$ --humid --community \$ARG2\$ --warning \$ARG3\$ --critical \$ARG4\$
}
# With PNP4Nagios ###########################################################################
Sample SNMPv2 checks
to add to the Nagios / Icinga file where your checks are located
#############################################################################################
Note:
Servertechs often have multiple sensors of the same type. With this check Nagios /
Icinga will alarm when any of the temperature, power or humidity thresholds is exceeded on
any of the specified type of sensor. This check automatically detects the number of sensors.
Note:
You will have to create separate configuration files in the PNP4Nagios "etc/check_commands"
directory. Use the sample files that exist there as a guide. Create these configuration files:
1) check_sentry3_amps.cfg
2) check_sentry3_humid.cfg
3) check_sentry3_temp.cfg
Make sure the following directives are applied in each file
CUSTOM_TEMPLATE = 1
DATATYPE = GAUGE
RRD_STORAGE_TYPE = SINGLE
Note:
PNP4Nagios chart template file gauge_single_rrd_one_chart_per_rra.php must be placed in
your "pnp4nagios/share/templates/" directory
Note:
If your charts are not displayed it could be due to the fact that PNP4Nagios did not
create a correctly configured .rrd and .xml file (AMPS, HUMIDITY,TEMPERATURE) in the
"pnp4nagios/var/perfdata/\$HOSTNAME\$/ directory because you restarted Nagios / Icinga
before you created the .cfg files above. The .rrd and .xml file for your check may have
to be deleted so that PNP4Nagios can recreate it automatically.
#############################################################################################
# Servertech test (AMPS)
define service{
use local-service,srv-pnp ; Name of service template to use
host_name servertech-cdu
service_description AMPS
check_command check_sentry3_amps!default_single_rra_per_chart!public!16!18
}
# Servertech test (HUMIDITY)
define service{
use local-service,srv-pnp ; Name of service template to use
host_name servertech-cdu
service_description HUMIDITY
check_command check_sentry3_humid!gauge_single_rrd_one_chart_per_rra!public!10:!75
}
# Servertech test (TEMPERATURE)
define service{
use local-service,srv-pnp ; Name of service template to use
host_name servertech-cdu
service_description TEMPERATURE
check_command check_sentry3_temp!gauge_single_rrd_one_chart_per_rra!public!35:!85!--fahrenheit
}
EOF
exit();
}