2476e90ba059098e7d37d259446a9bf60e6a89bf
Benjamin Renard Initial import from http://...

Benjamin Renard authored 13 years ago

1) #!/usr/bin/perl -w
2) # Check SMART status of ATA/SCSI disks, returning any usable metrics as perfdata.
3) # For usage information, run ./check_smart -h
4) #
5) # This script was created under contract for the US Government and is therefore Public Domain
6) #
7) # Changes and Modifications
8) # =========================
9) # Feb 3, 2009: Kurt Yoder - initial version of script 1.0
10) # Jan 27, 2010: Philippe Genonceaux - modifications for compatibility with megaraid, use smartmontool version >= 5.39 
Benjamin Renard Added 'fork' information in...

Benjamin Renard authored 13 years ago

11) # May 13, 2011: Benjamin Renard - "Fork" in a Git repository : http://git.zionetrix.net
Benjamin Renard Initial import from http://...

Benjamin Renard authored 13 years ago

12) # Add this line to /etc/sudoers: "nagios        ALL=(root) NOPASSWD: /usr/sbin/smartctl"
13) 
14) use strict;
15) use Getopt::Long;
16) 
17) use File::Basename qw(basename);
18) my $basename = basename($0);
19) 
20) my $revision = '$Revision: 1.0.1 $';
21) 
22) use lib '/usr/lib/nagios/plugins/';
23) use utils qw(%ERRORS &print_revision &support &usage);
24) 
25) $ENV{'PATH'}='/bin:/usr/bin:/sbin:/usr/sbin';
26) $ENV{'BASH_ENV'}=''; 
27) $ENV{'ENV'}='';
28) 
29) use vars qw($opt_d $opt_debug $opt_h $opt_i $opt_n $opt_v);
30) Getopt::Long::Configure('bundling');
31) GetOptions(
32) 	                  "debug"       => \$opt_debug,
33) 	"d=s" => \$opt_d, "device=s"    => \$opt_d,
34) 	"h"   => \$opt_h, "help"        => \$opt_h,
35) 	"i=s" => \$opt_i, "interface=s" => \$opt_i,
36) 	"n=s" => \$opt_n, "number=s"	=> \$opt_n,
37) 	"v"   => \$opt_v, "version"     => \$opt_v,
38) );
39) 
40) if ($opt_v) {
41) 	print_revision($basename,$revision);
42) 	exit $ERRORS{'OK'};
43) }
44) 
45) if ($opt_h) {
46) 	print_help(); 
47) 	exit $ERRORS{'OK'};
48) }
Benjamin Renard Added initial value to opti...

Benjamin Renard authored 13 years ago

49) my ($device, $interface, $number) = qw/0 0 0/;
Benjamin Renard Initial import from http://...

Benjamin Renard authored 13 years ago

50) if ($opt_d) {
51) 	unless($opt_i){
52) 		print "must specify an interface for $opt_d using -i/--interface!\n\n";
53) 		print_help();
54) 		exit $ERRORS{'UNKNOWN'};
55) 	}
56) 
57) 	if (-b $opt_d){
58) 		$device = $opt_d;
59) 	}
60) 	else{
61) 		print "$opt_d is not a valid block device!\n\n";
62) 		print_help();
63) 		exit $ERRORS{'UNKNOWN'};
64) 	}
65) 
66) 	if(grep {$opt_i eq $_} ('ata', 'scsi', 'megaraid')){
67) 		$interface = $opt_i;
68)                 if($interface eq 'megaraid'){
69)                     if(defined($opt_n)){
70)                         $number = $opt_n;
71)                         $interface = $opt_i.",".$number;
72)                     }
73)                     else{
74)                         print "must specify a physical disk number within the MegaRAID controller!\n\n";
75)                         print_help();
76)                         exit $ERRORS{'UNKNOWN'};
77)                     }
78)                 }
79) 	}
80) 	else{
81) 		print "invalid interface $opt_i for $opt_d!\n\n";
82) 		print_help();
83) 		exit $ERRORS{'UNKNOWN'};
84) 	}
85) }
86) else{
87) 	print "must specify a device!\n\n";
88) 	print_help();
89) 	exit $ERRORS{'UNKNOWN'};
90) }
91) my $smart_command = '/usr/bin/sudo /usr/sbin/smartctl';
92) my @error_messages = qw//;
93) my $exit_status = 'OK';
94) 
95) 
96) warn "###########################################################\n" if $opt_debug;
97) warn "(debug) CHECK 1: getting overall SMART health status\n" if $opt_debug;
98) warn "###########################################################\n\n\n" if $opt_debug;
99) 
100) my $full_command = "$smart_command -d $interface -H $device";
101) warn "(debug) executing:\n$full_command\n\n" if $opt_debug;
102) 
103) my @output = `$full_command`;
104) warn "(debug) output:\n@output\n\n" if $opt_debug;
105) 
106) # parse ata output, looking for "health status: passed"
107) my $found_status = 0;
108) my $line_str = 'SMART overall-health self-assessment test result: '; # ATA SMART line
109) my $ok_str = 'PASSED'; # ATA SMART OK string
110) 
Benjamin Renard Fixed error in SMART Health...

Benjamin Renard authored 13 years ago

111) if ($interface eq 'megaraid'.",".$number or $interface eq 'scsi'){
Benjamin Renard Initial import from http://...

Benjamin Renard authored 13 years ago

112) 	$line_str = 'SMART Health Status: '; # SCSI OR MEGARAID SMART line
113) 	$ok_str = 'OK'; #SCSI OR MEGARAID SMART OK string
114) }
115) 
116) foreach my $line (@output){
117) 	if($line =~ /$line_str(.+)/){
118) 		$found_status = 1;
119) 		warn "(debug) parsing line:\n$line\n\n" if $opt_debug;
120) 		if ($1 eq $ok_str) {
121) 			warn "(debug) found string '$ok_str'; status OK\n\n" if $opt_debug;
122) 		}
123) 		else {
124) 			warn "(debug) no '$ok_str' status; failing\n\n" if $opt_debug;
125) 			push(@error_messages, "Health status: $1");
126) 			escalate_status('CRITICAL');
127) 		}
128) 	}
129) }
130) 
131) unless ($found_status) {
132) 	push(@error_messages, 'No health status line found');
133) 	escalate_status('UNKNOWN');
134) }
135) 
136) 
137) warn "###########################################################\n" if $opt_debug;
138) warn "(debug) CHECK 2: getting silent SMART health check\n" if $opt_debug;
139) warn "###########################################################\n\n\n" if $opt_debug;
140) 
141) $full_command = "$smart_command -d $interface -q silent -A $device";
142) warn "(debug) executing:\n$full_command\n\n" if $opt_debug;
143) 
144) system($full_command);
145) my $return_code = $?;
146) warn "(debug) exit code:\n$return_code\n\n" if $opt_debug;
147) 
148) if ($return_code & 0x01) {
149) 	push(@error_messages, 'Commandline parse failure');
150) 	escalate_status('UNKNOWN');
151) }
152) if ($return_code & 0x02) {
153) 	push(@error_messages, 'Device could not be opened');
154) 	escalate_status('UNKNOWN');
155) }
156) if ($return_code & 0x04) {
157) 	push(@error_messages, 'Checksum failure');
158) 	escalate_status('WARNING');
159) }
160) if ($return_code & 0x08) {
161) 	push(@error_messages, 'Disk is failing');
162) 	escalate_status('CRITICAL');
163) }
164) if ($return_code & 0x10) {
165) 	push(@error_messages, 'Disk is in prefail');
166) 	escalate_status('WARNING');
167) }
168) if ($return_code & 0x20) {
169) 	push(@error_messages, 'Disk may be close to failure');
170) 	escalate_status('WARNING');
171) }
172) if ($return_code & 0x40) {
173) 	push(@error_messages, 'Error log contains errors');
174) 	escalate_status('WARNING');
175) }
176) if ($return_code & 0x80) {
177) 	push(@error_messages, 'Self-test log contains errors');
178) 	escalate_status('WARNING');
179) }
180) if ($return_code && !$exit_status) {
181) 	push(@error_messages, 'Unknown return code');
182) 	escalate_status('CRITICAL');
183) }
184) 
185) if ($return_code) {
186) 	warn "(debug) non-zero exit code, generating error condition\n\n" if $opt_debug;
187) }
188) else {
189) 	warn "(debug) zero exit code, status OK\n\n" if $opt_debug;
190) }
191) 
192) 
193) warn "###########################################################\n" if $opt_debug;
194) warn "(debug) CHECK 3: getting detailed statistics\n" if $opt_debug;
195) warn "(debug) information contains a few more potential trouble spots\n" if $opt_debug;
196) warn "(debug) plus, we can also use the information for perfdata/graphing\n" if $opt_debug;
197) warn "###########################################################\n\n\n" if $opt_debug;
198) 
199) $full_command = "$smart_command -d $interface -A $device";
200) warn "(debug) executing:\n$full_command\n\n" if $opt_debug;
201) @output = `$full_command`;
202) warn "(debug) output:\n@output\n\n" if $opt_debug;
203) my @perfdata = qw//;
204) 
205) # separate metric-gathering and output analysis for ATA vs SCSI SMART output
206) if ($interface eq 'ata'){
207) 	foreach my $line(@output){
208) 		# get lines that look like this:
209) 		#    9 Power_On_Minutes        0x0032   241   241   000    Old_age   Always       -       113h+12m
210) 		next unless $line =~ /^\s*\d+\s(\S+)\s+(?:\S+\s+){6}(\S+)\s+(\d+)/;
211) 		my ($attribute_name, $when_failed, $raw_value) = ($1, $2, $3);
Benjamin Renard Added exception for errors...

Benjamin Renard authored 13 years ago

212) 		if ($when_failed ne '-' && $when_failed ne 'In_the_past'){