Code

plugin to check printer status via snmp, includes page count as perfdata; perl plugin
authorSubhendu Ghosh <sghosh@users.sourceforge.net>
Sun, 18 Jan 2004 20:07:01 +0000 (20:07 +0000)
committerSubhendu Ghosh <sghosh@users.sourceforge.net>
Sun, 18 Jan 2004 20:07:01 +0000 (20:07 +0000)
git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@795 f882894a-f735-0410-b71e-b25c423dba1c

contrib/check_snmp_printer.pl [new file with mode: 0755]

diff --git a/contrib/check_snmp_printer.pl b/contrib/check_snmp_printer.pl
new file mode 100755 (executable)
index 0000000..9fc5fed
--- /dev/null
@@ -0,0 +1,605 @@
+#!/usr/local/bin/perl -w
+
+# check_snmp_printer - check for printer status via snmp
+#  Supports both standard PRINT-MIB (RFC-1759) and HP Enterprise print-mib
+#  that is supported by some of the older JetDirect interfaces
+
+# Acknowledgements:
+# the JetDirect code is taken from check_hpjd.c by Ethan Galstad
+#   
+#   The idea for the plugin (as well as some code) were taken from Jim
+#   Trocki's pinter alert script in his "mon" utility, found at
+#   http://www.kernel.org/software/mon
+#
+
+# Notes:
+# 'JetDirect' is copyrighted by Hewlett-Packard
+#
+#
+# License Information:
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+############################################################################
+#
+# TODO: Query HOST-RESOURCE MIB for a quick status
+#
+# hrPrinterStatus = .1.3.6.1.2.1.25.3.5.1;
+# hrPrinterDetectedErrorState = .1.3.6.1.2.1.25.3.5.1.2
+#
+# hrPrinterStatus OBJECT-TYPE
+#    SYNTAX     INTEGER {
+#                   other(1),
+#                   unknown(2),
+#                   idle(3),
+#                   printing(4),
+#                   warmup(5)
+#               }
+#
+# hrPrinterDetectedErrorState OBJECT-TYPE
+#    SYNTAX     OCTET STRING
+#    MAX-ACCESS read-only
+#    STATUS     current
+#    DESCRIPTION
+#        "This object represents any error conditions detected
+#        by the printer.  The error conditions are encoded as
+#        bits in an octet string, with the following
+#        definitions:
+#
+#             Condition         Bit #
+#
+#             lowPaper              0
+#
+#             noPaper               1
+#             lowToner              2
+#             noToner               3
+#             doorOpen              4
+#             jammed                5
+#             offline               6
+#             serviceRequested      7
+#             inputTrayMissing      8
+#             outputTrayMissing     9
+#             markerSupplyMissing  10
+#             outputNearFull       11
+#             outputFull           12
+#             inputTrayEmpty       13
+#             overduePreventMaint  14
+#
+#  
+#
+use strict;
+use Getopt::Long;
+use vars qw($opt_V $opt_h $opt_H $opt_P $opt_t $opt_d $session $error $answer $key
+   $response $PROGNAME $port $hostname );
+use lib  "utils.pm";
+use utils qw(%ERRORS &print_revision &support &usage );
+use Net::SNMP;
+
+sub print_help ();
+sub print_usage ();
+
+$ENV{'PATH'}='';
+$ENV{'BASH_ENV'}=''; 
+$ENV{'ENV'}='';
+
+# defaults 
+my $ptype = 1;                                                 # to standard RFC printer type
+my $state = $ERRORS{'UNKNOWN'};
+my $community = "public";
+my $snmp_version = 1;
+my $port = 161;
+
+Getopt::Long::Configure('bundling');
+GetOptions
+       ("d"   => \$opt_d, "debug"                      => \$opt_d,
+        "V"   => \$opt_V, "version"            => \$opt_V,
+        "P=s" => \$opt_P, "Printer=s"      => \$opt_P,    # printer type - HP or RFC
+        "v=i" => \$snmp_version, "snmp_version=i"  => \$snmp_version,
+        "p=i" => \$port, "port=i" => \$port,
+        "C=s" => \$community,"community=s" => \$community,
+        "h"   => \$opt_h, "help"               => \$opt_h,
+        "H=s" => \$opt_H, "hostname=s"         => \$opt_H);
+
+
+
+$PROGNAME = "check_snmp_printer";
+
+if ($opt_V) {
+       print_revision($PROGNAME,'$Revision$');
+       exit $ERRORS{'OK'};
+}
+
+if ($opt_h) {print_help(); exit $ERRORS{'OK'};}
+
+unless (defined $opt_H) {
+       print "No target hostname specified\n";
+       exit $ERRORS{"UNKNOWN"};
+}
+$hostname = $opt_H;
+if (! utils::is_hostname($hostname)){
+       usage(" $hostname did not match pattern\n");
+       exit $ERRORS{"UNKNOWN"};
+}
+
+if (defined $opt_P) {
+       if ($opt_P eq "HP" ) {
+               $ptype = 2;
+       }elsif ($opt_P eq "RFC" ) {
+               $ptype = 1;
+       }else{
+               print "Only \"HP\" and \"RFC\" are supported as printer options at this time.\n";
+               exit $ERRORS{"UNKNOWN"};
+       }
+}
+
+
+if ( $snmp_version =~ /[12]/ ) {
+               
+       ($session, $error) = Net::SNMP->session(
+             -hostname  => $hostname,
+             -community => $community,
+             -port      => $port,
+                 -version      => $snmp_version
+                  );
+
+       if (!defined($session)) {
+             $state='UNKNOWN';
+             $answer=$error;
+             print ("$state: no session - $answer\n");
+             exit $ERRORS{$state};
+       }
+
+       print "Opened session|" if (defined ($opt_d));
+               
+}elsif ( $snmp_version =~ /3/ ) {
+       $state='UNKNOWN';
+       print ("$state: No support for SNMP v3 yet\n");
+       exit $ERRORS{$state};
+}else{
+       $state='UNKNOWN';
+       print ("$state: No support for SNMP v$snmp_version yet\n");
+       exit $ERRORS{$state};
+}
+
+
+
+
+
+
+### main logic
+
+if ( $ptype == 1 ) {   # STD MIB
+       print "STD-MIB|" if (defined ($opt_d));
+
+       my %snmp_response;
+       my $snmp_index;
+       my $col_oid;
+       my %std_mib_inst_count ;
+       my %std_mib_instances;
+       my $display;
+       my $inst;
+       my $group;
+       
+
+       #### RFC1759 MIB OIDS
+
+       # sub-unit status - textual convention
+       my $subunit_status;   # integer from 0-126                                              
+                                               
+
+       # column oid - not instances
+       my %std_mib = (
+               std_mib_input_status =>                                 ".1.3.6.1.2.1.43.8.2.1.11",  # 2 element index
+               std_mib_input_name   =>                                 ".1.3.6.1.2.1.43.8.2.1.13",
+               std_mib_output_remaining_capacity =>    ".1.3.6.1.2.1.43.9.2.1.5", 
+               std_mib_output_status =>                                ".1.3.6.1.2.1.43.9.2.1.6",
+               std_mib_marker_tech =>                                  ".1.3.6.1.2.1.43.10.2.1.2",
+               std_mib_marker_counter_unit =>  ".1.3.6.1.2.1.43.10.2.1.3",
+               std_mib_marker_life_count =>            ".1.3.6.1.2.1.43.10.2.1.4",
+               std_mib_marker_status =>                                ".1.3.6.1.2.1.43.10.2.1.15",
+               std_mib_supplies_type =>                                ".1.3.6.1.2.1.43.11.1.1.5",
+               std_mib_supplies_level =>                               ".1.3.6.1.2.1.43.11.1.1.9",
+               std_mib_media_path_type =>                              ".1.3.6.1.2.1.43.13.4.1.9",
+               std_mib_media_path_status =>                    ".1.3.6.1.2.1.43.13.4.1.11",
+
+               std_mib_status_display =>                               ".1.3.6.1.2.1.43.16.5.1.2",  # 2 element index
+
+               std_mib_alert_sev_level =>                              ".1.3.6.1.2.1.43.18.1.1.2",
+               std_mib_alert_grp =>                                    ".1.3.6.1.2.1.43.18.1.1.4",
+               std_mib_alert_location =>                               ".1.3.6.1.2.1.43.18.1.1.5",
+
+       );
+
+       my %std_mib_marker_tech = (
+                                       1 => "other",
+                                       2 => "unknown",
+                                       3 => "electrophotographicLED",
+                                       4 => "electrophotographicLaser",
+                                       5 => "electrophotographicOther",
+                                       6 => "impactMovingHeadDotMatrix9pin",
+                                       7 => "impactMovingHeadDotMatrix24pin",
+                                       8 => "impactMovingHeadDotMatrixOther",
+                                       9 => "impactMovingHeadFullyFormed",
+                                       10 => "impactBand",
+                                       11 => "impactOther",
+                                       12 => "inkjectAqueous",
+                                       13 => "inkjetSolid",
+                                       14 => "inkjetOther",
+                                       15 => "pen",
+                                       16 => "thermalTransfer",
+                                       17 => "thermalSensitive",
+                                       18 => "thermalDiffusion",
+                                       19 => "thermalOther",
+                                       20 => "electroerosion",
+                                       21 => "electrostatic",
+                                       22 => "photographicMicrofiche",
+                                       23 => "photographicImagesetter",
+                                       24 => "photographicOther",
+                                       25 => "ionDeposition",
+                                       26 => "eBeam",
+                                       27 => "typesetter",
+       );
+       
+       my %std_mib_marker_counter_units = (
+                                       3 => "tenThousandthsOfInches",
+                                       4 => "micrometers",
+                                       5 => "characters",
+                                       6 => "lines",
+                                       7 => "impressions",
+                                       8 => "sheets",
+                                       9 => "dotRow",
+                                       11 => "hours",
+                                       16 => "feet",
+                                       17 => "meters",
+       );
+
+       my %std_mib_alert_groups = (
+               1 => "unspecifiedOther",
+               3 => "printerStorageMemory",  # hostResourcesMIBStorageTable
+               4 => "internalDevice",                  # hostResourcesMIBDeviceTable
+               5 => "generalPrinter",
+               6 => "cover",
+               7 => "localization",
+               8 => "input",
+               9 => "output",
+               10 => "marker",
+               11 => "markerSupplies",
+               12 => "markerColorant",
+               13 => "mediaPath",
+               14 => "connectionChannel",
+               15 => "interpreter",
+               16 => "consoleDisplayBuffer",
+               17 => "consoleLights",
+       );
+
+               
+       my %std_mib_prt_alert_code = (
+               1 => "other",                      # ok if on power save
+               2 => "unknown",
+       # -- codes common to serveral groups
+               3 => "coverOpen",
+               4 => "coverClosed",
+               5 => "interlockOpen",
+               6 => "interlockClosed",
+               7 => "configurationChange",
+               8 => "jam",                        # critical
+               # -- general Printer group
+               501 => "doorOpen",
+               502 => "doorClosed",
+               503 => "powerUp",
+               504 => "powerDown",
+               # -- Input Group
+               801 => "inputMediaTrayMissing",
+               802 => "inputMediaSizeChange",
+               803 => "inputMediaWeightChange",
+               804 => "inputMediaTypeChange",
+               805 => "inputMediaColorChange",
+               806 => "inputMediaFormPartsChange",
+               807 => "inputMediaSupplyLow",
+               808 => "inputMediaSupplyEmpty",
+               # -- Output Group
+               901 => "outputMediaTrayMissing",
+               902 => "outputMediaTrayAlmostFull",
+               903 => "outputMediaTrayFull",
+               # -- Marker group
+               1001 => "markerFuserUnderTemperature",
+               1002 => "markerFuserOverTemperature",
+               # -- Marker Supplies group
+               1101 => "markerTonerEmpty",
+               1102 => "markerInkEmpty",
+               1103 => "markerPrintRibbonEmpty",
+               1104 => "markerTonerAlmostEmpty",
+               1105 => "markerInkAlmostEmpty",
+               1106 => "markerPrintRibbonAlmostEmpty",
+               1107 => "markerWasteTonerReceptacleAlmostFull",
+               1108 => "markerWasteInkReceptacleAlmostFull",
+               1109 => "markerWasteTonerReceptacleFull",
+               1110 => "markerWasteInkReceptacleFull",
+               1111 => "markerOpcLifeAlmostOver",
+               1112 => "markerOpcLifeOver",
+               1113 => "markerDeveloperAlmostEmpty",
+               1114 => "markerDeveloperEmpty",
+               # -- Media Path Device Group
+               1301 => "mediaPathMediaTrayMissing",
+               1302 => "mediaPathMediaTrayAlmostFull",
+               1303 => "mediaPathMediaTrayFull",
+               # -- interpreter Group  
+               1501 => "interpreterMemoryIncrease",
+               1502 => "interpreterMemoryDecrease",
+               1503 => "interpreterCartridgeAdded",
+               1504 => "interpreterCartridgeDeleted",
+               1505 => "interpreterResourceAdded",
+               1506 => "interpreterResourceDeleted",
+       );
+
+       ## Need multiple passes as oids are all part of tables  
+       foreach $col_oid (sort keys %std_mib ){ 
+
+               if ( !defined( $response = $session->get_table($std_mib{$col_oid}) ) ) {
+                       print "Error col_oid $col_oid|" if (defined ($opt_d));
+
+                       if (! ($col_oid =~ m/std_mib_alert/ ) ) {             # alerts don't have to exist all the time!
+                               $answer=$session->error;
+                               $session->close;
+                               $state = 'CRITICAL';
+                               print ("$state: $answer for $std_mib{$col_oid}\n");
+                               exit $ERRORS{$state};
+                       }
+               }
+               
+               print "NoError col_oid $col_oid|" if (defined ($opt_d));
+               
+               foreach $key (keys %{$response}) {
+                       $key =~ /.*\.(\d+)\.(\d+)$/;     # all oids have a two part index appended
+                       $snmp_index = $1 . "." . $2;   
+                       print "\n$key => $col_oid.$snmp_index  = $response->{$key} \n" if (defined ($opt_d));
+                       $snmp_response{$key} = $response->{$key} ;
+                       
+                       $std_mib_inst_count{$col_oid} += 1 ;   # count how many instances
+                       $std_mib_instances{$col_oid} .= $snmp_index .":" ;
+
+               }
+       
+       }
+
+       #foreach $key ( keys %std_mib_inst_count) {
+       #       print "$key = $std_mib_inst_count{$key} $std_mib_instances{$key}  \n";
+       #}
+       # get (total) "page count" - perfdata
+       #print "\n \n $std_mib_instances{'std_mib_marker_tech'} \n";    
+       # how many marker technologies are in use?
+       my ($pg, $pt, $pfd);
+       my @mark_tech = split(/:/, $std_mib_instances{'std_mib_marker_tech'});
+       foreach $inst (sort @mark_tech){
+               $pfd = $std_mib_marker_tech{$snmp_response{$std_mib{'std_mib_marker_tech'}."." .$inst}} ;
+               $pfd .= ",".$snmp_response{$std_mib{'std_mib_marker_life_count'}.".".$inst};
+               $pfd .= ",".$std_mib_marker_counter_units{$snmp_response{$std_mib{'std_mib_marker_counter_unit'}.".".$inst}};
+               $pfd .= ";"; #perf data separator for multiple marker tech
+
+
+               print "pfd = $pfd\n" if (defined ($opt_d));
+       };
+
+       # combine all lines of status display into one line
+       #$std_mib_instances{'std_mib_status_display'} = substr($std_mib_instances{'std_mib_status_display'}, 1);
+       my @display_index = split(/:/,  $std_mib_instances{'std_mib_status_display'} );
+       
+       foreach $inst ( sort @display_index) {
+               $display .= $snmp_response{$std_mib{'std_mib_status_display'} . "." . $inst} . " ";
+       }
+
+
+
+       # see if there are any alerts
+       if (defined ( $std_mib_inst_count{'std_mib_alert_sev_level'} )  ) {
+               
+               if ( ( lc($display) =~ /save/  || lc($display) =~ /warm/ ) &&   $std_mib_inst_count{'std_mib_alert_sev_level'} == 1 ) {
+                       $state='OK';
+                       $answer = "Printer ok - $display";
+                       print $answer . "|$pfd\n";
+                       exit $ERRORS{$state};
+               }
+               
+               # sometime during transitions from power save to warming there are 2 alerts
+               # if the 2nd alert is for something else it should get caught in the
+               # next call since warmup typically is much smaller than check time
+               # interval.
+               if (  lc($display) =~ /warm/  &&        $std_mib_inst_count{'std_mib_alert_sev_level'} == 2 )   {
+                       $state='OK';
+                       $answer = "$state: Printer - $display";
+                       print $answer . "|$pfd\n";
+                       exit $ERRORS{$state};
+               }
+
+               
+               # We have alerts and the display does not say power save or warming up
+               $std_mib_instances{'std_mib_alert_sev_level'} = substr($std_mib_instances{'std_mib_alert_sev_level'}, 1);
+               @display_index = split(/:/,     $std_mib_instances{'std_mib_alert_sev_level'} );
+               $answer = "Alert location(s): ";
+               
+               for $inst (@display_index) {
+                       $state = 'WARNING';
+                       if ( $snmp_response{$std_mib{'std_mib_alert_location'} . "." . $inst} < 1) {
+                               $answer .= "unknown location ";
+                       }else{
+                               $answer .= $std_mib_prt_alert_code{$snmp_response{$std_mib{'std_mib_alert_location'} . "." . $inst} } . " ";
+                       
+                               #print $std_mib_prt_alert_code{$snmp_response{$std_mib{'std_mib_alert_location'}. "." . $inst}} ;
+                       }
+               }
+
+               print "$state: $answer|$pfd\n";
+               exit $ERRORS{$state};
+               
+       }else{
+               $state='OK';
+               $answer = "$state: Printer ok - $display ";
+               print $answer . "|$pfd\n";
+               exit $ERRORS{$state};
+
+       }
+       
+       
+       
+
+}
+elsif( $ptype == 2 ) {  # HP MIB - JetDirect
+       
+       #### HP MIB OIDS - instance OIDs
+       my $HPJD_LINE_STATUS=                   ".1.3.6.1.4.1.11.2.3.9.1.1.2.1.0";
+       my $HPJD_PAPER_STATUS=                  ".1.3.6.1.4.1.11.2.3.9.1.1.2.2.0";
+       my $HPJD_INTERVENTION_REQUIRED= ".1.3.6.1.4.1.11.2.3.9.1.1.2.3.0";
+       my $HPJD_GD_PERIPHERAL_ERROR=   ".1.3.6.1.4.1.11.2.3.9.1.1.2.6.0";
+       my $HPJD_GD_PAPER_JAM=                  ".1.3.6.1.4.1.11.2.3.9.1.1.2.8.0";
+       my $HPJD_GD_PAPER_OUT=                  ".1.3.6.1.4.1.11.2.3.9.1.1.2.9.0";
+       my $HPJD_GD_TONER_LOW=                  ".1.3.6.1.4.1.11.2.3.9.1.1.2.10.0";
+       my $HPJD_GD_PAGE_PUNT=                  ".1.3.6.1.4.1.11.2.3.9.1.1.2.11.0";
+       my $HPJD_GD_MEMORY_OUT=                 ".1.3.6.1.4.1.11.2.3.9.1.1.2.12.0";
+       my $HPJD_GD_DOOR_OPEN=                  ".1.3.6.1.4.1.11.2.3.9.1.1.2.17.0";
+       my $HPJD_GD_PAPER_OUTPUT=               ".1.3.6.1.4.1.11.2.3.9.1.1.2.19.0";
+       my $HPJD_GD_STATUS_DISPLAY=             ".1.3.6.1.4.1.11.2.3.9.1.1.3.0";
+       #define ONLINE          0
+       #define OFFLINE         1
+
+       my @hp_oids = ( $HPJD_LINE_STATUS,$HPJD_PAPER_STATUS,$HPJD_INTERVENTION_REQUIRED,$HPJD_GD_PERIPHERAL_ERROR,
+                               $HPJD_GD_PAPER_JAM,$HPJD_GD_PAPER_OUT,$HPJD_GD_TONER_LOW,$HPJD_GD_PAGE_PUNT,$HPJD_GD_MEMORY_OUT,
+                               $HPJD_GD_DOOR_OPEN,$HPJD_GD_PAPER_OUTPUT,$HPJD_GD_STATUS_DISPLAY);
+
+
+
+       
+       $state = $ERRORS{'OK'};
+
+       if (!defined($response = $session->get_request(@hp_oids))) {
+               $answer=$session->error;
+               $session->close;
+               $state = 'CRITICAL';
+               print ("$state: $answer \n");
+               exit $ERRORS{$state};
+       }
+
+       # cycle thru the responses and set the appropriate state
+       
+       if($response->{$HPJD_GD_PAPER_JAM} ) {
+               $state='WARNING';
+               $answer = "Paper Jam";
+       }
+       elsif($response->{$HPJD_GD_PAPER_OUT} ) {
+               $state='WARNING';
+               $answer = "Out of Paper";
+       }
+       elsif($response->{$HPJD_LINE_STATUS} ) {
+               if ($response->{$HPJD_LINE_STATUS} ne "POWERSAVE ON" ) {
+                       $state='WARNING';
+                       $answer = "Printer Offline";
+               }
+       }
+       elsif($response->{$HPJD_GD_PERIPHERAL_ERROR} ) {
+               $state='WARNING';
+               $answer = "Peripheral Error";
+       }
+       elsif($response->{$HPJD_INTERVENTION_REQUIRED} ) {
+               $state='WARNING';
+               $answer = "Intervention Required";
+       }
+       elsif($response->{$HPJD_GD_TONER_LOW} ) {
+               $state='WARNING';
+               $answer = "Toner Low";
+       }
+       elsif($response->{$HPJD_GD_MEMORY_OUT} ) {
+               $state='WARNING';
+               $answer = "Insufficient Memory";
+       }
+       elsif($response->{$HPJD_GD_DOOR_OPEN} ) {
+               $state='WARNING';
+               $answer = "Insufficient Memory";
+       }
+       elsif($response->{$HPJD_GD_PAPER_OUTPUT} ) {
+               $state='WARNING';
+               $answer = "OutPut Tray is Full";
+       }
+       elsif($response->{$HPJD_GD_PAGE_PUNT} ) {
+               $state='WARNING';
+               $answer = "Data too slow for Engine";
+       }
+       elsif($response->{$HPJD_PAPER_STATUS} ) {
+               $state='WARNING';
+               $answer = "Unknown Paper Error";
+       }
+       else            # add code to parse STATUS DISPLAY here
+       {
+               $state='OK';
+               $answer = "Printer ok - $response->{$HPJD_GD_STATUS_DISPLAY} ";
+       }
+
+       # print and exit
+
+       print "$state: $answer \n";
+       exit $ERRORS{$state};
+
+
+}
+else{  # 3rd printer type - not yet supported
+       
+       print "Printer type $opt_P has not been implemented\n";
+       $state='UNKNOWN';
+       exit $ERRORS{$state};
+
+}
+
+
+
+#### subroutines
+sub unit_status {
+       my $stat = shift;
+       
+
+}
+
+sub print_usage () {
+       print "Usage: $PROGNAME -H <host> [-C community] [-P HP or RFC] [-p port]  [-v snmp_version] [-h help]  [-V version]\n";
+}
+
+sub print_help () {
+       print_revision($PROGNAME,'$Revision$');
+       print "Copyright (c) 2002 Subhendu Ghosh/Ethan Galstad.
+
+This plugin reports the status of an network printer with an SNMP management
+module.
+
+";
+       print_usage();
+       print "
+-H, --hostname=HOST
+   Name or IP address of host to check
+-C --community
+   snmp community string (default: public)
+-P --Printer
+   supported values are \"HP\" for Jetdirect printers and
+   \"RFC\" for RFC 1759 Print MIB based implementations (default: RFC)
+-p --port
+   Port where snmp agent is listening (default: 161)
+-v --snmp_version
+   SNMP version to use (default: version 1)
+-h --help
+   This screen
+-V --version
+   Plugin version
+
+";
+       support();
+}
+
+
+