summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xcontrib/check_snmp_printer.pl605
1 files changed, 605 insertions, 0 deletions
diff --git a/contrib/check_snmp_printer.pl b/contrib/check_snmp_printer.pl
new file mode 100755
index 00000000..9fc5fedd
--- /dev/null
+++ b/contrib/check_snmp_printer.pl
@@ -0,0 +1,605 @@
1#!/usr/local/bin/perl -w
2
3# check_snmp_printer - check for printer status via snmp
4# Supports both standard PRINT-MIB (RFC-1759) and HP Enterprise print-mib
5# that is supported by some of the older JetDirect interfaces
6
7# Acknowledgements:
8# the JetDirect code is taken from check_hpjd.c by Ethan Galstad
9#
10# The idea for the plugin (as well as some code) were taken from Jim
11# Trocki's pinter alert script in his "mon" utility, found at
12# http://www.kernel.org/software/mon
13#
14
15# Notes:
16# 'JetDirect' is copyrighted by Hewlett-Packard
17#
18#
19# License Information:
20# This program is free software; you can redistribute it and/or modify
21# it under the terms of the GNU General Public License as published by
22# the Free Software Foundation; either version 2 of the License, or
23# (at your option) any later version.
24#
25# This program is distributed in the hope that it will be useful,
26# but WITHOUT ANY WARRANTY; without even the implied warranty of
27# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28# GNU General Public License for more details.
29#
30# You should have received a copy of the GNU General Public License
31# along with this program; if not, write to the Free Software
32# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33#
34############################################################################
35#
36# TODO: Query HOST-RESOURCE MIB for a quick status
37#
38# hrPrinterStatus = .1.3.6.1.2.1.25.3.5.1;
39# hrPrinterDetectedErrorState = .1.3.6.1.2.1.25.3.5.1.2
40#
41# hrPrinterStatus OBJECT-TYPE
42# SYNTAX INTEGER {
43# other(1),
44# unknown(2),
45# idle(3),
46# printing(4),
47# warmup(5)
48# }
49#
50# hrPrinterDetectedErrorState OBJECT-TYPE
51# SYNTAX OCTET STRING
52# MAX-ACCESS read-only
53# STATUS current
54# DESCRIPTION
55# "This object represents any error conditions detected
56# by the printer. The error conditions are encoded as
57# bits in an octet string, with the following
58# definitions:
59#
60# Condition Bit #
61#
62# lowPaper 0
63#
64# noPaper 1
65# lowToner 2
66# noToner 3
67# doorOpen 4
68# jammed 5
69# offline 6
70# serviceRequested 7
71# inputTrayMissing 8
72# outputTrayMissing 9
73# markerSupplyMissing 10
74# outputNearFull 11
75# outputFull 12
76# inputTrayEmpty 13
77# overduePreventMaint 14
78#
79#
80#
81use strict;
82use Getopt::Long;
83use vars qw($opt_V $opt_h $opt_H $opt_P $opt_t $opt_d $session $error $answer $key
84 $response $PROGNAME $port $hostname );
85use lib "utils.pm";
86use utils qw(%ERRORS &print_revision &support &usage );
87use Net::SNMP;
88
89sub print_help ();
90sub print_usage ();
91
92$ENV{'PATH'}='';
93$ENV{'BASH_ENV'}='';
94$ENV{'ENV'}='';
95
96# defaults
97my $ptype = 1; # to standard RFC printer type
98my $state = $ERRORS{'UNKNOWN'};
99my $community = "public";
100my $snmp_version = 1;
101my $port = 161;
102
103Getopt::Long::Configure('bundling');
104GetOptions
105 ("d" => \$opt_d, "debug" => \$opt_d,
106 "V" => \$opt_V, "version" => \$opt_V,
107 "P=s" => \$opt_P, "Printer=s" => \$opt_P, # printer type - HP or RFC
108 "v=i" => \$snmp_version, "snmp_version=i" => \$snmp_version,
109 "p=i" => \$port, "port=i" => \$port,
110 "C=s" => \$community,"community=s" => \$community,
111 "h" => \$opt_h, "help" => \$opt_h,
112 "H=s" => \$opt_H, "hostname=s" => \$opt_H);
113
114
115
116$PROGNAME = "check_snmp_printer";
117
118if ($opt_V) {
119 print_revision($PROGNAME,'$Revision$');
120 exit $ERRORS{'OK'};
121}
122
123if ($opt_h) {print_help(); exit $ERRORS{'OK'};}
124
125unless (defined $opt_H) {
126 print "No target hostname specified\n";
127 exit $ERRORS{"UNKNOWN"};
128}
129$hostname = $opt_H;
130if (! utils::is_hostname($hostname)){
131 usage(" $hostname did not match pattern\n");
132 exit $ERRORS{"UNKNOWN"};
133}
134
135if (defined $opt_P) {
136 if ($opt_P eq "HP" ) {
137 $ptype = 2;
138 }elsif ($opt_P eq "RFC" ) {
139 $ptype = 1;
140 }else{
141 print "Only \"HP\" and \"RFC\" are supported as printer options at this time.\n";
142 exit $ERRORS{"UNKNOWN"};
143 }
144}
145
146
147if ( $snmp_version =~ /[12]/ ) {
148
149 ($session, $error) = Net::SNMP->session(
150 -hostname => $hostname,
151 -community => $community,
152 -port => $port,
153 -version => $snmp_version
154 );
155
156 if (!defined($session)) {
157 $state='UNKNOWN';
158 $answer=$error;
159 print ("$state: no session - $answer\n");
160 exit $ERRORS{$state};
161 }
162
163 print "Opened session|" if (defined ($opt_d));
164
165}elsif ( $snmp_version =~ /3/ ) {
166 $state='UNKNOWN';
167 print ("$state: No support for SNMP v3 yet\n");
168 exit $ERRORS{$state};
169}else{
170 $state='UNKNOWN';
171 print ("$state: No support for SNMP v$snmp_version yet\n");
172 exit $ERRORS{$state};
173}
174
175
176
177
178
179
180### main logic
181
182if ( $ptype == 1 ) { # STD MIB
183 print "STD-MIB|" if (defined ($opt_d));
184
185 my %snmp_response;
186 my $snmp_index;
187 my $col_oid;
188 my %std_mib_inst_count ;
189 my %std_mib_instances;
190 my $display;
191 my $inst;
192 my $group;
193
194
195 #### RFC1759 MIB OIDS
196
197 # sub-unit status - textual convention
198 my $subunit_status; # integer from 0-126
199
200
201 # column oid - not instances
202 my %std_mib = (
203 std_mib_input_status => ".1.3.6.1.2.1.43.8.2.1.11", # 2 element index
204 std_mib_input_name => ".1.3.6.1.2.1.43.8.2.1.13",
205 std_mib_output_remaining_capacity => ".1.3.6.1.2.1.43.9.2.1.5",
206 std_mib_output_status => ".1.3.6.1.2.1.43.9.2.1.6",
207 std_mib_marker_tech => ".1.3.6.1.2.1.43.10.2.1.2",
208 std_mib_marker_counter_unit => ".1.3.6.1.2.1.43.10.2.1.3",
209 std_mib_marker_life_count => ".1.3.6.1.2.1.43.10.2.1.4",
210 std_mib_marker_status => ".1.3.6.1.2.1.43.10.2.1.15",
211 std_mib_supplies_type => ".1.3.6.1.2.1.43.11.1.1.5",
212 std_mib_supplies_level => ".1.3.6.1.2.1.43.11.1.1.9",
213 std_mib_media_path_type => ".1.3.6.1.2.1.43.13.4.1.9",
214 std_mib_media_path_status => ".1.3.6.1.2.1.43.13.4.1.11",
215
216 std_mib_status_display => ".1.3.6.1.2.1.43.16.5.1.2", # 2 element index
217
218 std_mib_alert_sev_level => ".1.3.6.1.2.1.43.18.1.1.2",
219 std_mib_alert_grp => ".1.3.6.1.2.1.43.18.1.1.4",
220 std_mib_alert_location => ".1.3.6.1.2.1.43.18.1.1.5",
221
222 );
223
224 my %std_mib_marker_tech = (
225 1 => "other",
226 2 => "unknown",
227 3 => "electrophotographicLED",
228 4 => "electrophotographicLaser",
229 5 => "electrophotographicOther",
230 6 => "impactMovingHeadDotMatrix9pin",
231 7 => "impactMovingHeadDotMatrix24pin",
232 8 => "impactMovingHeadDotMatrixOther",
233 9 => "impactMovingHeadFullyFormed",
234 10 => "impactBand",
235 11 => "impactOther",
236 12 => "inkjectAqueous",
237 13 => "inkjetSolid",
238 14 => "inkjetOther",
239 15 => "pen",
240 16 => "thermalTransfer",
241 17 => "thermalSensitive",
242 18 => "thermalDiffusion",
243 19 => "thermalOther",
244 20 => "electroerosion",
245 21 => "electrostatic",
246 22 => "photographicMicrofiche",
247 23 => "photographicImagesetter",
248 24 => "photographicOther",
249 25 => "ionDeposition",
250 26 => "eBeam",
251 27 => "typesetter",
252 );
253
254 my %std_mib_marker_counter_units = (
255 3 => "tenThousandthsOfInches",
256 4 => "micrometers",
257 5 => "characters",
258 6 => "lines",
259 7 => "impressions",
260 8 => "sheets",
261 9 => "dotRow",
262 11 => "hours",
263 16 => "feet",
264 17 => "meters",
265 );
266
267 my %std_mib_alert_groups = (
268 1 => "unspecifiedOther",
269 3 => "printerStorageMemory", # hostResourcesMIBStorageTable
270 4 => "internalDevice", # hostResourcesMIBDeviceTable
271 5 => "generalPrinter",
272 6 => "cover",
273 7 => "localization",
274 8 => "input",
275 9 => "output",
276 10 => "marker",
277 11 => "markerSupplies",
278 12 => "markerColorant",
279 13 => "mediaPath",
280 14 => "connectionChannel",
281 15 => "interpreter",
282 16 => "consoleDisplayBuffer",
283 17 => "consoleLights",
284 );
285
286
287 my %std_mib_prt_alert_code = (
288 1 => "other", # ok if on power save
289 2 => "unknown",
290 # -- codes common to serveral groups
291 3 => "coverOpen",
292 4 => "coverClosed",
293 5 => "interlockOpen",
294 6 => "interlockClosed",
295 7 => "configurationChange",
296 8 => "jam", # critical
297 # -- general Printer group
298 501 => "doorOpen",
299 502 => "doorClosed",
300 503 => "powerUp",
301 504 => "powerDown",
302 # -- Input Group
303 801 => "inputMediaTrayMissing",
304 802 => "inputMediaSizeChange",
305 803 => "inputMediaWeightChange",
306 804 => "inputMediaTypeChange",
307 805 => "inputMediaColorChange",
308 806 => "inputMediaFormPartsChange",
309 807 => "inputMediaSupplyLow",
310 808 => "inputMediaSupplyEmpty",
311 # -- Output Group
312 901 => "outputMediaTrayMissing",
313 902 => "outputMediaTrayAlmostFull",
314 903 => "outputMediaTrayFull",
315 # -- Marker group
316 1001 => "markerFuserUnderTemperature",
317 1002 => "markerFuserOverTemperature",
318 # -- Marker Supplies group
319 1101 => "markerTonerEmpty",
320 1102 => "markerInkEmpty",
321 1103 => "markerPrintRibbonEmpty",
322 1104 => "markerTonerAlmostEmpty",
323 1105 => "markerInkAlmostEmpty",
324 1106 => "markerPrintRibbonAlmostEmpty",
325 1107 => "markerWasteTonerReceptacleAlmostFull",
326 1108 => "markerWasteInkReceptacleAlmostFull",
327 1109 => "markerWasteTonerReceptacleFull",
328 1110 => "markerWasteInkReceptacleFull",
329 1111 => "markerOpcLifeAlmostOver",
330 1112 => "markerOpcLifeOver",
331 1113 => "markerDeveloperAlmostEmpty",
332 1114 => "markerDeveloperEmpty",
333 # -- Media Path Device Group
334 1301 => "mediaPathMediaTrayMissing",
335 1302 => "mediaPathMediaTrayAlmostFull",
336 1303 => "mediaPathMediaTrayFull",
337 # -- interpreter Group
338 1501 => "interpreterMemoryIncrease",
339 1502 => "interpreterMemoryDecrease",
340 1503 => "interpreterCartridgeAdded",
341 1504 => "interpreterCartridgeDeleted",
342 1505 => "interpreterResourceAdded",
343 1506 => "interpreterResourceDeleted",
344 );
345
346 ## Need multiple passes as oids are all part of tables
347 foreach $col_oid (sort keys %std_mib ){
348
349 if ( !defined( $response = $session->get_table($std_mib{$col_oid}) ) ) {
350 print "Error col_oid $col_oid|" if (defined ($opt_d));
351
352 if (! ($col_oid =~ m/std_mib_alert/ ) ) { # alerts don't have to exist all the time!
353 $answer=$session->error;
354 $session->close;
355 $state = 'CRITICAL';
356 print ("$state: $answer for $std_mib{$col_oid}\n");
357 exit $ERRORS{$state};
358 }
359 }
360
361 print "NoError col_oid $col_oid|" if (defined ($opt_d));
362
363 foreach $key (keys %{$response}) {
364 $key =~ /.*\.(\d+)\.(\d+)$/; # all oids have a two part index appended
365 $snmp_index = $1 . "." . $2;
366 print "\n$key => $col_oid.$snmp_index = $response->{$key} \n" if (defined ($opt_d));
367 $snmp_response{$key} = $response->{$key} ;
368
369 $std_mib_inst_count{$col_oid} += 1 ; # count how many instances
370 $std_mib_instances{$col_oid} .= $snmp_index .":" ;
371
372 }
373
374 }
375
376 #foreach $key ( keys %std_mib_inst_count) {
377 # print "$key = $std_mib_inst_count{$key} $std_mib_instances{$key} \n";
378 #}
379 # get (total) "page count" - perfdata
380 #print "\n \n $std_mib_instances{'std_mib_marker_tech'} \n";
381 # how many marker technologies are in use?
382 my ($pg, $pt, $pfd);
383 my @mark_tech = split(/:/, $std_mib_instances{'std_mib_marker_tech'});
384 foreach $inst (sort @mark_tech){
385 $pfd = $std_mib_marker_tech{$snmp_response{$std_mib{'std_mib_marker_tech'}."." .$inst}} ;
386 $pfd .= ",".$snmp_response{$std_mib{'std_mib_marker_life_count'}.".".$inst};
387 $pfd .= ",".$std_mib_marker_counter_units{$snmp_response{$std_mib{'std_mib_marker_counter_unit'}.".".$inst}};
388 $pfd .= ";"; #perf data separator for multiple marker tech
389
390
391 print "pfd = $pfd\n" if (defined ($opt_d));
392 };
393
394 # combine all lines of status display into one line
395 #$std_mib_instances{'std_mib_status_display'} = substr($std_mib_instances{'std_mib_status_display'}, 1);
396 my @display_index = split(/:/, $std_mib_instances{'std_mib_status_display'} );
397
398 foreach $inst ( sort @display_index) {
399 $display .= $snmp_response{$std_mib{'std_mib_status_display'} . "." . $inst} . " ";
400 }
401
402
403
404 # see if there are any alerts
405 if (defined ( $std_mib_inst_count{'std_mib_alert_sev_level'} ) ) {
406
407 if ( ( lc($display) =~ /save/ || lc($display) =~ /warm/ ) && $std_mib_inst_count{'std_mib_alert_sev_level'} == 1 ) {
408 $state='OK';
409 $answer = "Printer ok - $display";
410 print $answer . "|$pfd\n";
411 exit $ERRORS{$state};
412 }
413
414 # sometime during transitions from power save to warming there are 2 alerts
415 # if the 2nd alert is for something else it should get caught in the
416 # next call since warmup typically is much smaller than check time
417 # interval.
418 if ( lc($display) =~ /warm/ && $std_mib_inst_count{'std_mib_alert_sev_level'} == 2 ) {
419 $state='OK';
420 $answer = "$state: Printer - $display";
421 print $answer . "|$pfd\n";
422 exit $ERRORS{$state};
423 }
424
425
426 # We have alerts and the display does not say power save or warming up
427 $std_mib_instances{'std_mib_alert_sev_level'} = substr($std_mib_instances{'std_mib_alert_sev_level'}, 1);
428 @display_index = split(/:/, $std_mib_instances{'std_mib_alert_sev_level'} );
429 $answer = "Alert location(s): ";
430
431 for $inst (@display_index) {
432 $state = 'WARNING';
433 if ( $snmp_response{$std_mib{'std_mib_alert_location'} . "." . $inst} < 1) {
434 $answer .= "unknown location ";
435 }else{
436 $answer .= $std_mib_prt_alert_code{$snmp_response{$std_mib{'std_mib_alert_location'} . "." . $inst} } . " ";
437
438 #print $std_mib_prt_alert_code{$snmp_response{$std_mib{'std_mib_alert_location'}. "." . $inst}} ;
439 }
440 }
441
442 print "$state: $answer|$pfd\n";
443 exit $ERRORS{$state};
444
445 }else{
446 $state='OK';
447 $answer = "$state: Printer ok - $display ";
448 print $answer . "|$pfd\n";
449 exit $ERRORS{$state};
450
451 }
452
453
454
455
456}
457elsif( $ptype == 2 ) { # HP MIB - JetDirect
458
459 #### HP MIB OIDS - instance OIDs
460 my $HPJD_LINE_STATUS= ".1.3.6.1.4.1.11.2.3.9.1.1.2.1.0";
461 my $HPJD_PAPER_STATUS= ".1.3.6.1.4.1.11.2.3.9.1.1.2.2.0";
462 my $HPJD_INTERVENTION_REQUIRED= ".1.3.6.1.4.1.11.2.3.9.1.1.2.3.0";
463 my $HPJD_GD_PERIPHERAL_ERROR= ".1.3.6.1.4.1.11.2.3.9.1.1.2.6.0";
464 my $HPJD_GD_PAPER_JAM= ".1.3.6.1.4.1.11.2.3.9.1.1.2.8.0";
465 my $HPJD_GD_PAPER_OUT= ".1.3.6.1.4.1.11.2.3.9.1.1.2.9.0";
466 my $HPJD_GD_TONER_LOW= ".1.3.6.1.4.1.11.2.3.9.1.1.2.10.0";
467 my $HPJD_GD_PAGE_PUNT= ".1.3.6.1.4.1.11.2.3.9.1.1.2.11.0";
468 my $HPJD_GD_MEMORY_OUT= ".1.3.6.1.4.1.11.2.3.9.1.1.2.12.0";
469 my $HPJD_GD_DOOR_OPEN= ".1.3.6.1.4.1.11.2.3.9.1.1.2.17.0";
470 my $HPJD_GD_PAPER_OUTPUT= ".1.3.6.1.4.1.11.2.3.9.1.1.2.19.0";
471 my $HPJD_GD_STATUS_DISPLAY= ".1.3.6.1.4.1.11.2.3.9.1.1.3.0";
472 #define ONLINE 0
473 #define OFFLINE 1
474
475 my @hp_oids = ( $HPJD_LINE_STATUS,$HPJD_PAPER_STATUS,$HPJD_INTERVENTION_REQUIRED,$HPJD_GD_PERIPHERAL_ERROR,
476 $HPJD_GD_PAPER_JAM,$HPJD_GD_PAPER_OUT,$HPJD_GD_TONER_LOW,$HPJD_GD_PAGE_PUNT,$HPJD_GD_MEMORY_OUT,
477 $HPJD_GD_DOOR_OPEN,$HPJD_GD_PAPER_OUTPUT,$HPJD_GD_STATUS_DISPLAY);
478
479
480
481
482 $state = $ERRORS{'OK'};
483
484 if (!defined($response = $session->get_request(@hp_oids))) {
485 $answer=$session->error;
486 $session->close;
487 $state = 'CRITICAL';
488 print ("$state: $answer \n");
489 exit $ERRORS{$state};
490 }
491
492 # cycle thru the responses and set the appropriate state
493
494 if($response->{$HPJD_GD_PAPER_JAM} ) {
495 $state='WARNING';
496 $answer = "Paper Jam";
497 }
498 elsif($response->{$HPJD_GD_PAPER_OUT} ) {
499 $state='WARNING';
500 $answer = "Out of Paper";
501 }
502 elsif($response->{$HPJD_LINE_STATUS} ) {
503 if ($response->{$HPJD_LINE_STATUS} ne "POWERSAVE ON" ) {
504 $state='WARNING';
505 $answer = "Printer Offline";
506 }
507 }
508 elsif($response->{$HPJD_GD_PERIPHERAL_ERROR} ) {
509 $state='WARNING';
510 $answer = "Peripheral Error";
511 }
512 elsif($response->{$HPJD_INTERVENTION_REQUIRED} ) {
513 $state='WARNING';
514 $answer = "Intervention Required";
515 }
516 elsif($response->{$HPJD_GD_TONER_LOW} ) {
517 $state='WARNING';
518 $answer = "Toner Low";
519 }
520 elsif($response->{$HPJD_GD_MEMORY_OUT} ) {
521 $state='WARNING';
522 $answer = "Insufficient Memory";
523 }
524 elsif($response->{$HPJD_GD_DOOR_OPEN} ) {
525 $state='WARNING';
526 $answer = "Insufficient Memory";
527 }
528 elsif($response->{$HPJD_GD_PAPER_OUTPUT} ) {
529 $state='WARNING';
530 $answer = "OutPut Tray is Full";
531 }
532 elsif($response->{$HPJD_GD_PAGE_PUNT} ) {
533 $state='WARNING';
534 $answer = "Data too slow for Engine";
535 }
536 elsif($response->{$HPJD_PAPER_STATUS} ) {
537 $state='WARNING';
538 $answer = "Unknown Paper Error";
539 }
540 else # add code to parse STATUS DISPLAY here
541 {
542 $state='OK';
543 $answer = "Printer ok - $response->{$HPJD_GD_STATUS_DISPLAY} ";
544 }
545
546 # print and exit
547
548 print "$state: $answer \n";
549 exit $ERRORS{$state};
550
551
552}
553else{ # 3rd printer type - not yet supported
554
555 print "Printer type $opt_P has not been implemented\n";
556 $state='UNKNOWN';
557 exit $ERRORS{$state};
558
559}
560
561
562
563#### subroutines
564sub unit_status {
565 my $stat = shift;
566
567
568}
569
570sub print_usage () {
571 print "Usage: $PROGNAME -H <host> [-C community] [-P HP or RFC] [-p port] [-v snmp_version] [-h help] [-V version]\n";
572}
573
574sub print_help () {
575 print_revision($PROGNAME,'$Revision$');
576 print "Copyright (c) 2002 Subhendu Ghosh/Ethan Galstad.
577
578This plugin reports the status of an network printer with an SNMP management
579module.
580
581";
582 print_usage();
583 print "
584-H, --hostname=HOST
585 Name or IP address of host to check
586-C --community
587 snmp community string (default: public)
588-P --Printer
589 supported values are \"HP\" for Jetdirect printers and
590 \"RFC\" for RFC 1759 Print MIB based implementations (default: RFC)
591-p --port
592 Port where snmp agent is listening (default: 161)
593-v --snmp_version
594 SNMP version to use (default: version 1)
595-h --help
596 This screen
597-V --version
598 Plugin version
599
600";
601 support();
602}
603
604
605