New smart-intercept-spindown didn't accept all formats of input coming to it - the status line we were trying to detect broken status of doesn't appear on most devices
156 lines
6.7 KiB
Bash
Executable file
156 lines
6.7 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
# For those disks like some of my SAS drives where `smartctl
|
|
# --nocheck=standby` and `hdparm -C` actually spins up the disk,
|
|
# detect whether a disk is spun down with sdparm commands, and don't
|
|
# invoke smartctl if it is. Otherwise, some of our other disks like
|
|
# our 16TB SATA drives on Dell Perc controllers give unreliable status to `sdparm
|
|
# --command=sense`, but `smartctl --nocheck=standby` does seem to
|
|
# reliably detect their spundown state anyway, so we continue to
|
|
# supply `--nocheck=standby` to cover this case.
|
|
|
|
# While we're here, we might as well try transform the mimimal output
|
|
# smartctl gives us on SAS drives into something we can parse too, so
|
|
# we can at least get temperatures for hddtemp_smartctl's use. We
|
|
# also detect nvme drives and pass off a request to smartctlnvme for
|
|
# it to give us smartctl style output on them.
|
|
|
|
final_arg="${@: -1}"
|
|
|
|
convert_sas() {
|
|
read_initial=true
|
|
read_data=false
|
|
device_model=
|
|
device_product=
|
|
data=
|
|
local exit_code=0
|
|
exit_condition=false
|
|
{
|
|
read line || exit_condition=true
|
|
while ! $exit_condition ; do
|
|
case "$read_initial,$read_data,$line" in
|
|
true,false,*DATA\ SECTION*)
|
|
read_initial=false
|
|
read_data=true
|
|
echo "Device Model: $device_vendor $device_product"
|
|
echo
|
|
echo "$line"
|
|
|
|
read line
|
|
if [[ "$line" == SMART\ Health\ Status: ]] ; then
|
|
if [[ "$line" == *OK ]] ; then
|
|
exit_code=0
|
|
else
|
|
exit_code=8
|
|
fi
|
|
echo "$line"
|
|
echo
|
|
read line
|
|
fi
|
|
|
|
echo "ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE"
|
|
continue # reparse the new line
|
|
;;
|
|
true,false,Vendor:*)
|
|
device_vendor="$( echo "$line" | sed 's/Vendor: *//' )"
|
|
echo "$line"
|
|
;;
|
|
true,false,Product:*)
|
|
device_product="$( echo "$line" | sed 's/Product: *//' )"
|
|
echo "$line"
|
|
;;
|
|
true*)
|
|
echo "$line"
|
|
;;
|
|
false,true,Current\ Drive\ Temperature:*)
|
|
temp="$( echo "$line" | sed 's/.*Temperature: *// ; s/ C$//' )"
|
|
;;
|
|
false,true,Drive\ Trip\ Temperature:*)
|
|
temp_threshold="$( echo "$line" | sed 's/.*Drive Trip Temperature: *// ; s/ C$//' )"
|
|
hundred_minus_temp="$( printf "%03.f" "$( echo "100 - $temp" | bc -l )" )"
|
|
echo "194 Temperature_Celsius null $hundred_minus_temp $hundred_minus_temp 000 Old_age Always - $temp (Min/Max 0/$temp_threshold)"
|
|
;;
|
|
false,true,Accumulated\ power\ on\ time,\ hours:minutes:*)
|
|
hours="$( echo "$line" | sed 's/.*hours:minutes // ; s/:.*//' )"
|
|
# minutes="$( echo "$line" | sed 's/.*hours:minutes // ; s/.*://' )"
|
|
# hours="$( echo "scale=2 ; $hours + $minutes/60" | bc -l )"
|
|
echo "9 Power_On_Hours null 100 100 000 Old_age Always - $hours"
|
|
;;
|
|
false,true,Specified\ cycle\ count\ over\ device\ lifetime:*)
|
|
start_stop_cycles_threshold="$( echo "$line" | sed 's/.*Specified cycle count over device lifetime: *//' )"
|
|
;;
|
|
false,true,Accumulated\ start-stop\ cycles:*)
|
|
start_stop_cycles="$( echo "$line" | sed 's/.*Accumulated start-stop cycles: *//' )"
|
|
hundred_minus_cycles="$( printf "%03.f" "$( echo "100 - 100*$start_stop_cycles/$start_stop_cycles_threshold" | bc -l )" )"
|
|
echo "12 Power_Cycle_Count null $hundred_minus_cycles $hundred_minus_cycles 000 Pre-fail Always - $start_stop_cycles"
|
|
;;
|
|
false,true,Specified\ load-unload\ count\ over\ device\ lifetime:*)
|
|
load_unload_cycles_threshold="$( echo "$line" | sed 's/.*Specified load-unload count over device lifetime: *//' )"
|
|
;;
|
|
false,true,Accumulated\ load-unload\ cycles:*)
|
|
load_unload_cycles="$( echo "$line" | sed 's/.*Accumulated load-unload cycles: *//' )"
|
|
hundred_minus_cycles="$( printf "%03.f" "$( echo "100 - 100*$load_unload_cycles/$load_unload_cycles_threshold" | bc -l )" )"
|
|
echo "193 Load_Cycle_Count null $hundred_minus_cycles $hundred_minus_cycles 000 Pre-fail Always - $load_unload_cycles"
|
|
;;
|
|
false,true,Elements\ in\ grown\ defect\ list:*)
|
|
defects="$( echo "$line" | sed 's/.*Elements in grown defect list: //' )"
|
|
echo "5 Reallocated_Sector_Ct null 100 100 001 Pre-fail Always - $defects"
|
|
;;
|
|
false,true,Non-medium\ error\ count:*)
|
|
errors="$( echo "$line" | sed 's/.*Non-medium error count: //' )"
|
|
echo "1 Raw_Read_Error_Rate null 100 100 001 Pre-fail Always - $errors"
|
|
;;
|
|
*)
|
|
data="$data
|
|
$line"
|
|
;;
|
|
esac
|
|
read line || exit_condition=true
|
|
done
|
|
} <<< "$1"
|
|
if [ -n "$data" ] ; then
|
|
echo
|
|
echo "=== SAS DATA ==="
|
|
echo "$data"
|
|
fi
|
|
|
|
return $exit_code
|
|
}
|
|
|
|
if [ "1" = --version ] ; then
|
|
# allow munin smart_ check to test for support of --nocheck=standby to ensure it doesnt' then run hdparm
|
|
exec smartctl "$@"
|
|
fi
|
|
|
|
if sdparm --command=sense "$final_arg" 2>/dev/null | grep -e "Standby condition" -e "Idle condition" ; then
|
|
# exit code success rather than code 2 like smartctl by default
|
|
# Could do similar output with hdparm -C, but smartctl
|
|
# --nocheck=standby,0 correctly detects that
|
|
exit
|
|
fi
|
|
|
|
smart_output=$( smartctl --nocheck=idle,0 "$@" )
|
|
exit_code=$?
|
|
|
|
case "$smart_output" in
|
|
*Transport*protocol:*SAS*)
|
|
convert_sas "$smart_output"
|
|
convert_exit=$?
|
|
|
|
# FIXME: should work out a proper exit code precedence rule
|
|
if (( $convert_exit > $exit_code )) ; then
|
|
exit $convert_exit
|
|
fi
|
|
exit $exit_code
|
|
;;
|
|
*NVMe*Version*)
|
|
# to transform smartctl nvme output to more resemble
|
|
# traditional output so existing munin plugins can monitor it
|
|
exec /usr/local/bin/smartctlnvme "$@"
|
|
;;
|
|
*)
|
|
echo "$smart_output"
|
|
;;
|
|
esac
|
|
|
|
exit $exit_code
|