File: //usr/lib/nagios/plugins/check_printer
#!/usr/bin/perl
# nagios: -epn
#
# Copyright (c) 2007,2011 Eric F Crist
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 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.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT OWNER OR
# CONTRIBUTORS 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.
#
# $Id: check_printer 363 2014-07-23 14:37:59Z ecrist $
# $HeadURL: trunk/nagios/check_printer $
use strict;
use warnings;
sub load_module {
my @names = @_;
my $module;
for my $name (@names) {
my $file = $name;
# requires need either a bare word or a file name
$file =~ s{::}{/}gsxm;
$file .= '.pm';
eval {
require $file;
$name->import(qw(%ERRORS));
$module = $name;
};
last if $module;
}
return $module;
}
my $plugin_module;
BEGIN {
$plugin_module = load_module( 'Monitoring::Plugin', 'Nagios::Plugin' );
}
use Getopt::Long;
use Pod::Usage;
'$Revision: 363 $' =~ m/Revision: (\d+)/;
my $revision = $1;
'$HeadURL: trunk/nagios/check_printer $' =~ m/HeadURL: ([\w\:\/\-\.\_]+) /;
my $src_url = $1;
my $debug = 0;
my ($host, $warning, $critical, @ignore);
my $community = "public";
our %getopts;
Getopt::Long::Configure("bundling");
GetOptions(
"h|host=s" => \$host,
"C|community=s" => \$community,
"w|warn=i" => \$warning,
"c|crit=i" => \$critical,
"i=i" => \@ignore,
'V|version' => sub { print '$Id: check_printer 363 2014-07-23 14:37:59Z ecrist $' ."\n"; exit 0 },
"d|debug" => \$debug,
"man" => sub { pod2usage(-exitstatus => 0, -verbose => 2); exit 0 }
) or pod2usage(2);
pod2usage(2) unless (defined($host));
my $base_oid = ".1.3.6.1.2.1.43.11.1.1";
my $type_oid = "3.1";
my $name_oid = "6.1";
my $uom_oid = "7.1";
my $max_oid = "8.1";
my $curr_oid = "9.1";
my $loop;
my $comm = $ARGV[1];
my @vars = ("snmpwalk -On -v 1 -c $community $host $base_oid.$name_oid",
"snmpwalk -On -v 1 -c $community $host $base_oid.$uom_oid",
"snmpwalk -On -v 1 -c $community $host $base_oid.$max_oid",
"snmpwalk -On -v 1 -c $community $host $base_oid.$curr_oid");
my(@values, @names, @max, @min);
our %uom = ( "4" => "µm",
"7" => "impressions",
"8" => "pages",
"11" => "hrs",
"12" => "oz/1000",
"13" => "gr/10",
"14" => "gr/100",
"15" => "mL",
"16" => "feet",
"17" => "meters",
"18" => "items",
"19" => "%");
foreach(@vars){
@values = (@values, split /\n/, `$_`);
if ($? != 0){
print "Printer Supplies UNKNOWN";
exit 3;
}
}
if ($debug){
use Data::Dumper;
print Dumper(\@values);
}
my %finvalues;
my $ignore = join('|', @ignore);
foreach(@values){
# matching the following line
# $1 $2 $3
# .1.3.6.1.2.1.43.11.1.1.6.1.1 = STRING: "Black Cartridge"
$_ =~ m/^([\.\d]+) = ([\w-]+):[\s\"]+([\(\)\-\d\w\s,\/:]+)\"*$/ or next;
my $loid = $1;
my $ltype = $2;
my $string = $3;
if ($loid =~ m/\.(${ignore})$/){
next;
}
if ($ltype =~ m/HEX/i){
# hex string, convert to ascii
$string = join "", map {chr hex $_ } split m/ /, $string;
}
$finvalues{"$loid"} = $string;
}
my %status;
# get OID field numbers for matching later
while (my ($key, $value) = each(%finvalues)){
## sort this array into an associative in the following format:
# $status['name'] : Supply Name
# $status['curr'] : Supply Status
# $status['max'] : Supply Level When New
my $search = quotemeta("$base_oid.$name_oid");
if ($key =~ /^$search\.([\d\.]+)$/){
## we'll assume a name
$status{$value}{"sub"} = $1;
} else {
}
}
# get maximum values, matching on OID field number
while (my ($key, $value) = each(%finvalues)){
my $search = quotemeta("$base_oid.$max_oid");
if ($key =~ /^$search\.([\d\.]+)$/){
## assign it to the other variable
## search the existing keys, find the one we want
foreach my $subvalue (values %status){
if ($subvalue->{"sub"} eq $1){
$subvalue->{"max"} = $value;
}
}
}
}
# get current value, matching on OID field number
while (my ($key, $value) = each(%finvalues)){
my $search = quotemeta("$base_oid.$curr_oid");
if ($key =~ /^$search\.([\d\.]+)$/){
## assign it to the other variable
## search the existing keys, find the one we want
foreach my $subvalue (values %status){
if ($subvalue->{"sub"} eq $1){
$subvalue->{"curr"} = $value;
}
}
}
}
# get uom, add it to data
while (my ($key, $value) = each(%finvalues)){
my $search = quotemeta("$base_oid.$uom_oid");
if ($key =~ /^$search\.([\d\.]+)$/){
## assign it to the other variable
## search the existing keys, find the one we want
foreach my $subvalue (values %status){
if ($subvalue->{"sub"} eq $1){
$subvalue->{"uom"} = $uom{$value};
}
}
}
}
## Assemble performance data and error string.
my $perf_str = "";
my $is_warn = 0;
my $is_crit = 0;
my $err_str = "";
while (my($key, $value) = each(%status)){
my ($maximum, $current);
if (!exists($value->{"curr"}) || $value->{"curr"} == -3){
## we can process as yes/no
$current = 100;
## Override the critical/warning, since they're moot
$critical = 0;
$warning = 0;
} elsif (($value->{"max"} == -2) and ($value->{"uom"} ne '%')){
## we don't know (-2 == unknown) the max and can't compute
next;
} else {
$maximum = $value->{"max"};
}
if (!exists($value->{"curr"}) || $value->{"curr"} < 0){
## weird value, set to 0 for math reasons
$current = 0;
} else {
$current = round(($value->{"curr"} / $maximum) * 100);
}
my $lcurrent;
if (($key =~ m/waste/i) or ($key =~ m/Toneruppsamlare/i) or ($key =~ m/Restonner/i)){
# invert the $current as waste is calculated in reverse
if ($value->{"curr"} == -3){
$lcurrent = 0;
} else {
$lcurrent = $maximum - $current;
}
} else {
$lcurrent = $current;
}
if ($lcurrent < $critical){
$is_crit = $is_crit + 1;
if ($err_str eq ""){
$err_str = "$key";
} else {
$err_str = "$err_str, $key";
}
} elsif ($lcurrent < $warning){
$is_warn = $is_warn + 1;
if ($err_str eq ""){
$err_str = "$key";
} else {
$err_str = "$err_str, $key";
}
}
if ($debug){
print "Key: $key\nCur: $current\nWarn: $warning\nCrit: $critical\n";
}
$perf_str = "$perf_str '$key'=$current%;$warning;$critical;0;100 ";
}
if ($debug){
print Dumper(\%status);
print "\n\n############ ATTENTION ############\n";
print "You have debug enabled. If asked to enable debug by the Debian Maintainer,\n";
print "please send all of the output to the Debian Bug Tracking System, either by \n";
print "replying to an existing bug or by opening a new bug.\n";
print '$Id: check_printer 363 2014-07-23 14:37:59Z ecrist $'."\n\n";
}
if ($is_crit){
print "$err_str CRITICAL. See http://$ARGV[0] | $perf_str\n";
exit 2;
} elsif ($is_warn){
print "$err_str WARNING. See http://$ARGV[0] | $perf_str\n";
exit 1;
} else {
print "Printer Supplies OK | $perf_str\n";
exit 0;
}
###
### subroutines here
###
sub round {
my($number) = shift;
return int($number + .5 * ($number <=> 0));
}
__END__
=head1 check_printer
check_printer - Gather supply metrics from a printer via SNMP query
=head1 SYNOPSIS
check_printer [options]
Options:
-h, --host Printer hostname or IP address.
-C, --community SNMP community string, defaults to "public"
-w, --warn Warning threshold
-c, --crit Critical threshold
-i, --ignore Supply ignore. See man page for more information (--man)
-V, --version Prints version string and exits
-d, --debug Prints debug output, useful when reporting a problem to the developer, or getting index numbers for --ignore
--man Prints man page
=head1 DESCRIPTION
B<check_printer> is a Perl script that retrieves supply metrics from printers using the snmpwalk command.
=head1 OPTIONS
=over
=item -h, --host
Defines the host or IP address passed to snmpwalk.
=item -C, --community
Identifies the SNMP community string. Requires read access only.
=item -w, --warn
Value at which a warning is generated. For example, if -w 10 is set, when
supply levels fall to 10% or below, a warning will be sent as part of the
performance data.
=item -c, --crit
Value at which a critical alert is generated. This number should be lower
than --warn is set, but this is not enforced.
=item -i, --ignore
Supply index that should be ignore from the output. Multiple values are
accepted, separately:
=over
check_printer -i 1 -i 2
=back
Will exclude supply indexes 1 and 2. To get the supply index list, run the
check_printer utility with --debug defined and the top of the output will
list available supply metrics as follows:
=over
$VAR1 = [
'.1.3.6.1.2.1.43.11.1.1.6.1.1 = STRING: "Black Toner"',
'.1.3.6.1.2.1.43.11.1.1.6.1.2 = STRING: "Drum Unit"',
'.1.3.6.1.2.1.43.11.1.1.7.1.1 = INTEGER: 13',
'.1.3.6.1.2.1.43.11.1.1.7.1.2 = INTEGER: 7',
'.1.3.6.1.2.1.43.11.1.1.8.1.1 = INTEGER: -2',
'.1.3.6.1.2.1.43.11.1.1.8.1.2 = INTEGER: -2',
'.1.3.6.1.2.1.43.11.1.1.9.1.1 = INTEGER: -3',
'.1.3.6.1.2.1.43.11.1.1.9.1.2 = INTEGER: 0'
];
=back
In the above example, we are looking for the OID string starting with
B<.1.3.6.1.2.1.43.11.1.1.6.1> and the index is the last number. To exclude the
Drum Unit, pass I<-i 2> to check_printer
=item -V, --version
Print the check_printer version string and exits.
=item -d, --debug
Outputs debug information. If you are having problems with a printer or device,
send the debug output to B<ecrist@secure-computing.net> and identify your printer
model and manufacturer.
=item --man
Prints this man page. :)