����JFIF��x�x����'
| Server IP : 78.140.185.180 / Your IP : 216.73.216.170 Web Server : LiteSpeed System : Linux cpanel13.v.fozzy.com 4.18.0-513.11.1.lve.el8.x86_64 #1 SMP Thu Jan 18 16:21:02 UTC 2024 x86_64 User : builderbox ( 1072) PHP Version : 7.3.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /proc/1630575/task/1630575/root/lib64/nagios/plugins/base/ |
Upload File : |
#!/usr/bin/env perl
use strict;
use warnings;
no if $] >= 5.018, warnings => 'experimental::smartmatch';
use Getopt::Long;
use Pod::Usage;
my $path = '/usr/sbin/smartctl';
my %E_STATE = (
'OK' => 0,
'WARNING' => 1,
'CRITICAL' => 2,
'UNKNOWN' => 3,
);
my (
$type, $drives, $sudo, $verbose,
$help, $device, $devmath, $temp,
$raid, $warning, $critical, $exclude_failed,
);
GetOptions(
'device=s' => \$device,
'devmath=s' => \$devmath,
't|type=s' => \$type,
'd|drives=s' => \$drives,
's|sudo' => \$sudo,
'p|path=s' => \$path,
'h|help' => \$help,
'r|raid=s' => \$raid,
'temp' => \$temp,
'w|warning=i' => \$warning,
'c|critical=i' => \$critical,
'ef|exclude-failed=s' => \$exclude_failed,
);
pod2usage( -verbose => 2 )
if $help;
pod2usage(1)
if !defined $raid
and (!defined $type
or !defined( $device or $devmath ) );
=head1 SYNOPSIS
$ check_smart [options] [--device device or --devmath math]
=head1 OPTIONS
=over 5
=item B<--device>
Set device. Example /dev/sda
=item B<--devmath>
Set device. Example "/dev/sg[1-9]" or "/dev/sg[1..9]"
=item B<--type> or B<-t>
Set device type. For additional info use smartctl --help
=item B<--drives> or B<-d>
Set drive numbers for check smart. Allow format: 1,2,3..7,24-27.
=item B<--path> or B<-p>
Set path to smartctl. Default /usr/sbin/smartctl
=item B<--sudo> or B<-s>
Use sudo for smartctl command or need run script as root
=item B<--temp>
print only status string and temperature data
=item B<--raid> or B<-r>
autodetected all disks connected to raid controller. Example --raid perc
Now support only perc raid controllers.
=item B<--warning> or B<-w>
Warning hard drive temp
=item B<--critical> or B<-c>
Critical hard drive temp
=item B<--exclude-failed> or B<-e>
Exclude failed smart attribute, value for attribute or value for all attributes
=item B<--help> or B<-h>
this help information
=back
=head1 DESCRIPTION
Examples for some raid-controllers:
Adaptec: check_smart -t sat --devmath "/dev/sg[1..27]"
MegaRaid: check_smart -t sat+megaraid --drives 6-9 --device /dev/sda
Perc:
sas: check_smart_custom --device /dev/sda --type megaraid --drives 6,7
ssd: check_smart_custom --device /dev/sda --type sat+megaraid --drives 1-5
Autodetect all perc disks
check_smart_custom --raid perc
Required installed omreport util and started srvadmin-services.sh
Examples use --exclude-failed option:
--exclude-failed="Airflow_Temperature_Cel=In_the_past,Reallocated_Event_Count=,=In_the_past"
Airflow_Temperature_Cel=In_the_past - skip failed value In_the_past for Airflow_Temperature_Cel
Reallocated_Event_Count= - skip any value for Reallocated_Event_Count
=In_the_past - skip this value for any attributes
=cut
# validate args and prepare data
if ( $> and !$sudo ) {
print "you are not root\n";
exit $E_STATE{'UNKNOWN'};
}
if ( !-X $path ) {
print "smartctl not found, please set path to executable smartctl file";
exit $E_STATE{'UNKNOWN'};
}
# parse drives or devices
my %devices;
if ( $raid && $raid eq 'perc' ) {
my $omreport = '/opt/dell/srvadmin/bin/omreport';
if ( !-x $omreport ) {
my $run = `which omreport`;
$omreport = $run if !$?;
if ( -x $omreport or $? ) {
print "omreport not installed on this server\n";
exit $E_STATE{'UNKNOWN'};
}
}
require XML::LibXML;
my ( $out, $xml );
my $cmd_prefix = $sudo ? "sudo $omreport" : "$omreport";
$out = `$cmd_prefix storage controller -fmt xml`;
$xml = XML::LibXML->new( '1.0', 'UTF-8' );
$xml = $xml->load_xml( string => $out );
for my $controller (
$xml->findnodes('/OMA/Controllers/DCStorageObject/ControllerNum') )
{
my $c = $controller->textContent;
$xml = XML::LibXML->new( '1.0', 'UTF-8' );
$out = `$cmd_prefix storage vdisk controller=$c -fmt xml`;
$xml = $xml->load_xml( string => $out );
for my $dev ( $xml->findnodes('/OMA/VirtualDisks/DCStorageObject') ) {
next if !$dev->getElementsByTagName('DeviceID');
my $devid = $dev->getElementsByTagName('DeviceID');
my $devname = $dev->getElementsByTagName('DeviceName');
$xml = XML::LibXML->new( '1.0', 'UTF-8' );
$out
= `$cmd_prefix storage pdisk controller=$c vdisk=$devid -fmt xml`;
$xml = $xml->load_xml( string => $out );
for my $pd ( $xml->findnodes('/OMA/ArrayDisks/DCStorageObject') )
{
my $pdid = $pd->getElementsByTagName('DeviceID');
my $pdproto = $pd->getElementsByTagName('BusProtocol');
# 7-sata, 8-sas
my $pdtype
= "$pdproto" == 7 ? 'sat+megaraid'
: "$pdproto" == 8 ? 'megaraid'
: die 'disk type not defined';
$devices{$pdid}{'type'} = $pdtype;
$devices{$pdid}{'device'} = $devname;
$drives = 1;
}
}
}
}
else {
if ( defined $drives ) {
my @prep_drives = split /,/, $drives;
for my $drive (@prep_drives) {
# push @devices, $drive if $drive =~ m/^\d+$/;
# push @devices, $1 .. $5
# if $drive =~ m/^(\d+)\s?((\.\.)|(-))\s?(\d+)$/;
if ( $drive =~ m/^\d+$/ ) {
$devices{$drive}{'type'} = $type;
$devices{$drive}{'device'} = $device;
}
elsif ( $drive =~ m/^(\d+)\s?((\.\.)|(-))\s?(\d+)$/ ) {
for ( $1 .. $5 ) {
$devices{$_}{'type'} = $type;
$devices{$_}{'device'} = $device;
}
}
}
}
elsif ( !defined $drives and $device ) {
#push @devices, $device;
my @devices = split( ',', $device );
map { $devices{$_}{'device'} = $_; $devices{$_}{'type'} = $type }
@devices;
}
elsif ($devmath) {
my ( $dev_prefix, $dev_premath ) = ( $1, $2 )
if $devmath =~ m/(\S+)(\[\S+\]|\(\S+\))/;
if ( !$dev_premath ) {
print "Device not matched";
exit $E_STATE{'UNKNOWN'};
}
my ( $dev_start, $dev_end ) = ( $1, $5 )
if $dev_premath =~ m/\(?\[?(\w+)\s?((\.\.)|(-))\s?(\w+)\]?\)?/;
#push @devices, "$dev_prefix$_" for $dev_start .. $dev_end;
$devices{"$dev_prefix$_"}{'type'} = $type for $dev_start .. $dev_end;
$devices{"$dev_prefix$_"}{'device'} = $device
for $dev_start .. $dev_end;
}
}
if ( !%devices ) {
print "Device not found\n";
exit $E_STATE{'UNKNOWN'};
}
# parse exclude
my %exclude_failed;
if ($exclude_failed) {
my @excludes = split /,/, $exclude_failed;
for my $exclude (@excludes) {
my ( $attr, $value ) = split /=/, $exclude;
if ( $attr && $value ) {
push @{ $exclude_failed{$attr} }, $value;
}
elsif ( $attr && !$value ) {
push @{ $exclude_failed{attrs} }, $attr;
}
elsif ( !$attr && $value ) {
push @{ $exclude_failed{values} }, $value;
}
}
}
# set default temp
$warning = 60 unless $warning;
$critical = 70 unless $critical;
# work
my $exit_status = 'OK';
my $exit_status_local = 'OK';
my $exit_status_temp = 'OK';
my $status_string = '';
my $perfdata_string = '';
sub return_status {
my $request_status = shift;
if ( $request_status eq 'WARNING' ) {
return if ( $exit_status or $exit_status_local ) eq 'CRITICAL';
}
if ( $request_status eq 'UNKNOWN' ) {
return if ( $exit_status or $exit_status_local ) eq 'WARNING';
return if ( $exit_status or $exit_status_local ) eq 'CRITICAL';
}
$exit_status = $request_status;
$exit_status_local = $request_status;
}
sub temp_status {
my $temp_value = shift;
my $temp_status
= ( $temp_value >= $critical ) ? 'CRITICAL'
: ( $temp_value >= $warning ) ? 'WARNING'
: ( $temp_value <= 0 ) ? 'UNKNOWN'
: 'OK';
return if $temp_status eq 'OK';
if ( $temp_status eq 'WARNING' ) {
return if ( $exit_status or $exit_status_local ) eq 'CRITICAL';
}
if ( $temp_status eq 'UNKNOWN' ) {
return if ( $exit_status or $exit_status_local ) eq 'WARNING';
return if ( $exit_status or $exit_status_local ) eq 'CRITICAL';
}
$exit_status_temp = $temp_status;
}
foreach my $dev ( sort keys %devices ) {
my $type = $devices{$dev}{'type'};
my $device = $devices{$dev}{'device'};
my @error_messages = qw//;
$exit_status_local = 'OK';
my ( $label,, $perfdata_label, $smart_overall_state, $smart_silent_check,
$smart_detailed_state, );
if ( defined $drives ) {
$label = "$device: $type,$dev - ";
$perfdata_label = "$device,$dev";
$smart_overall_state = "$path -d $type,$dev -H $device";
$smart_silent_check = "$path -d $type,$dev -q silent -A $device";
$smart_detailed_state = "$path -d $type,$dev -A $device";
}
else {
$label = "$dev: $type - ";
$perfdata_label = "$dev";
$smart_overall_state = "$path -d $type -H $dev";
$smart_silent_check = "$path -d $type -q silent -A $dev";
$smart_detailed_state = "$path -d $type -A $dev";
}
# overall status
my @result = $sudo ? `sudo $smart_overall_state` : `$smart_overall_state`;
my $output_mode = "";
my $found_status = 0;
my $line_str_ata
= 'SMART overall-health self-assessment test result: '; # ATA
my $ok_str_ata = 'PASSED'; # ATA SMART OK string
my $line_str_scsi = 'SMART Health Status: '; # SCSI
my $ok_str_scsi = 'OK'; #SCSI and CCISS SMART OK string
foreach my $line (@result) {
if ( $line =~ /$line_str_scsi(.+)/ ) {
$found_status = 1;
$output_mode = "scsi";
if ( $1 ne $ok_str_scsi ) {
push( @error_messages, "Health status: $1" );
return_status('WARNING');
}
}
if ( $line =~ /$line_str_ata(.+)/ ) {
$found_status = 1;
$output_mode = "ata";
if ( $1 ne $ok_str_ata ) {
push( @error_messages, "Health status: $1" );
return_status('WARNING');
}
}
}
unless ($found_status) {
push( @error_messages, 'No health status line found' );
return_status('UNKNOWN');
}
# silent SMART health check
# https://www.smartmontools.org/browser/trunk/smartmontools/smartctl.8.in
$sudo ? system("sudo $smart_silent_check") : system($smart_silent_check);
my $return_code = $? >> 8;
if ( $return_code & ( 1 << 0 ) ) {
push( @error_messages, 'Command line did not parse.' );
return_status('UNKNOWN');
}
if ( $return_code & ( 1 << 1 ) ) {
push( @error_messages, 'Device open failed' );
return_status('UNKNOWN');
}
if ( $return_code & ( 1 << 2 ) ) {
push( @error_messages, 'Checksum error in a SMART data structure.' );
return_status('WARNING');
}
if ( $return_code & ( 1 << 3 ) ) {
push( @error_messages, 'Disk failing.' );
return_status('WARNING');
}
if ( $return_code & ( 1 << 4 ) ) {
push( @error_messages, 'We found prefail Attributes <= threshold.' );
return_status('WARNING');
}
if ( $return_code & ( 1 << 5 ) ) {
push( @error_messages, 'Smart ok but below threshold.' );
return_status('WARNING');
}
if ( $return_code & ( 1 << 6 ) ) {
push( @error_messages,
'The device error log contains records of errors.' );
return_status('WARNING');
}
if ( $return_code & ( 1 << 7 ) ) {
push( @error_messages,
'The device self-test log contains records of errors.' );
return_status('WARNING');
}
if ( $return_code && !$exit_status_local ) {
push( @error_messages, 'Unknown return code.' );
return_status('UNKNOWN');
}
# detailed statistics
@result = $sudo ? `sudo $smart_detailed_state` : `$smart_detailed_state`;
if ( $output_mode =~ "ata" ) {
my $reallocated_sector_ct;
my %temp;
foreach my $line (@result) {
next
unless $line
=~ /^\s*(\d+)\s(\S+)\s+(?:\S+\s+)\s+(\d+)\s+(?:\S+\s+)\s+(\d+)\s+(?:\S+\s+){2}(\S+)\s+(\d+)/;
my (
$attribute_id, $attribute_name, $current_value,
$thresh_value, $when_failed, $raw_value
) = ( $1, $2, $3, $4, $5, $6 );
# skip some attributes
next
if ( grep { $_ eq $attribute_name }
qw(Power_On_Minutes Unknown_Attribute) );
# skip Reallocated_Event_Count if Reallocated_Sector_Ct in normal state
# 30 magic number
$reallocated_sector_ct = $current_value - $thresh_value
if ( $attribute_name eq 'Reallocated_Sector_Ct' );
next
if ( $attribute_name eq 'Reallocated_Event_Count'
&& $current_value <= $thresh_value
&& $reallocated_sector_ct > 30 );
if ( $attribute_name
=~ /Airflow_Temperature_Cel|Temperature_Celsius/
&& $attribute_id != 231 )
{
$temp{$perfdata_label}{$attribute_name}
= sprintf( "%d", $raw_value );
}
if ( $when_failed ne '-' ) {
push( @error_messages,
"Attribute $attribute_name failed at $when_failed" );
my $status
= $attribute_name ~~ @{ $exclude_failed{attrs} } ? 'OK'
: $when_failed ~~ @{ $exclude_failed{values} } ? 'OK'
: $when_failed ~~ @{ $exclude_failed{$attribute_name} }
? 'OK'
: 'WARNING';
return_status($status);
}
if ( $current_value <= $thresh_value ) {
push( @error_messages,
"Attribute $attribute_name failed: value ($current_value) less thresh_value ($thresh_value)"
);
my $status
= $attribute_name ~~ @{ $exclude_failed{attrs} } ? 'OK'
: 'WARNING';
return_status($status);
}
}
# build perfdata string
foreach my $label ( keys %temp ) {
$perfdata_string .=
$temp{$label}{'Temperature_Celsius'}
? "\'$label"
. '_temp\'='
. $temp{$label}{'Temperature_Celsius'} . ';'
. $warning . ';'
. $critical . ';; '
: $temp{$label}{'Airflow_Temperature_Cel'} ? "\'$label"
. '_tempAir\'='
. $temp{$label}{'Airflow_Temperature_Cel'} . ';'
. $warning . ';'
. $critical . ';; '
: "\'$label" . '_temp\'=0;;;; ';
temp_status(
$temp{$label}{'Temperature_Celsius'}
? $temp{$label}{'Temperature_Celsius'}
: $temp{$label}{'Airflow_Temperature_Cel'}
? $temp{$label}{'Airflow_Temperature_Cel'}
: 0
);
}
}
elsif ( $output_mode =~ "scsi" ) {
foreach my $line (@result) {
my (
$current_temperature, $max_temperature,
$current_start_stop, $max_start_stop
) = qw//;
if ( $line =~ /Current Drive Temperature:\s+(\d+)/ ) {
$current_temperature = $1;
}
elsif ( $line =~ /Drive Trip Temperature:\s+(\d+)/ ) {
$max_temperature = $1;
}
elsif ( $line =~ /Current start stop count:\s+(\d+)/ ) {
$current_start_stop = $1;
}
elsif ( $line =~ /Recommended maximum start stop count:\s+(\d+)/ )
{
$max_start_stop = $1;
}
elsif ( $line =~ /Elements in grown defect list:\s+(\d+)/ ) {
my $defectlist = $1;
if ( $defectlist > 0 ) {
push( @error_messages,
"$defectlist Elements in grown defect list" );
return_status('OK');
}
}
if ($current_temperature) {
$perfdata_string
.= "\'$perfdata_label"
. '_temp\'='
. sprintf( "%d", $current_temperature ) . ';'
. $warning . ';'
. $critical . ';; ';
temp_status($current_temperature);
}
if ( ( $current_temperature && $max_temperature )
&& ( $current_temperature >= $max_temperature ) )
{
push( @error_messages,
'Disk temperature is higher than maximum' );
return_status('WARNING');
}
if ( ( $current_start_stop && $max_start_stop )
&& ( $current_start_stop >= $max_start_stop ) )
{
push( @error_messages,
'Disk start_stop is higher than maximum' );
return_status('WARNING');
}
}
}
else {
push( @error_messages, 'Device mode not math' );
return_status('UNKNOWN');
}
if ( $exit_status_local ne 'OK' ) {
$status_string .= $label . join( ', ', @error_messages ) . ".\n";
}
else {
$status_string .= $label . "no SMART errors detected" . ".\n";
$status_string .= $label . join( ', ', @error_messages ) . ".\n"
if @error_messages;
}
}
if ($temp) {
print "$exit_status_temp";
print "|$perfdata_string\n";
exit $E_STATE{$exit_status_temp};
}
else {
$exit_status
= $E_STATE{$exit_status} > $E_STATE{$exit_status_temp}
? $exit_status
: $exit_status_temp;
print "$exit_status";
print ": \n$status_string";
print "|$perfdata_string\n";
exit $E_STATE{$exit_status};
}
1;