����JFIF��x�x����'
Server IP : 78.140.185.180 / Your IP : 3.15.31.240 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 : /usr/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;