Przeglądaj źródła

plugin to check printer status via snmp, includes page count as perfdata; perl plugin

git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@795 f882894a-f735-0410-b71e-b25c423dba1c
Subhendu Ghosh 22 lat temu
rodzic
commit
f152e45257
1 zmienionych plików z 605 dodań i 0 usunięć
  1. 605 0
      contrib/check_snmp_printer.pl

+ 605 - 0
contrib/check_snmp_printer.pl

@@ -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();
+}
+
+
+