diff --git a/checkmk/checkmk-files/smart b/checkmk/checkmk-files/smart index 6e28c91faf990e511e00ab7b98081c9512719aa9..d0636ca191a930404c5cb1c5319caa9a26a3ff18 100644 --- a/checkmk/checkmk-files/smart +++ b/checkmk/checkmk-files/smart @@ -1,30 +1,21 @@ #!/bin/bash -# +------------------------------------------------------------------+ -# | ____ _ _ __ __ _ __ | -# | / ___| |__ ___ ___| | __ | \/ | |/ / | -# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / | -# | | |___| | | | __/ (__| < | | | | . \ | -# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ | -# | | -# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de | -# +------------------------------------------------------------------+ -# -# This file is part of Check_MK. -# The official homepage is at http://mathias-kettner.de/check_mk. -# -# check_mk is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation in version 2. check_mk is distributed -# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- -# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. See the GNU General Public License for more de- -# tails. You should have received a copy of the GNU General Public -# License along with GNU Make; see the file COPYING. If not, write -# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -# Boston, MA 02110-1301 USA. - - - +# Copyright (C) 2019 tribe29 GmbH - License: GNU General Public License v2 +# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and +# conditions defined in the file COPYING, which is part of this source code package. + +# Reason for this no-op: shellcheck disable=... before the first command disables the error for the +# entire script. +: + +# Disable unused variable error (needed to keep track of version) +# shellcheck disable=SC2034 +CMK_VERSION="2.0.0p12" + +# Function to replace "if type [somecmd]" idiom +# 'command -v' tends to be more robust vs 'which' and 'type' based tests +inpath() { + command -v "${1:?No command to test}" >/dev/null 2>&1 +} # This will be called on LSI based raidcontrollers and accesses # the SMART data of SATA disks attached to a SAS Raid HBA via @@ -39,7 +30,7 @@ megaraid_info() fi echo "$PDINFO" | \ - while read line ; do + while read -r line ; do case "$line" in # FIRST LINE "Enclosure Device ID"*) #Enclosure Device ID: 252 @@ -63,8 +54,8 @@ megaraid_info() MODEL=$( echo "$line" | awk '{print $3}') # /dev/sdc ATA SAMSUNG_SSD_830 5 Reallocated_Sector_Ct 0x0033 100 100 010 Pre-fail Always - - smartctl -d megaraid,${LOG_DEV_ID} -v 9,raw48 -A /dev/sg0 | \ - grep Always | egrep -v '^190(.*)Temperature(.*)' | \ + smartctl -d megaraid,"${LOG_DEV_ID}" -v 9,raw48 -A /dev/sg0 | \ + grep Always | grep -E -v '^190(.*)Temperature(.*)' | \ sed "s|^|Enc${ENC}/Slot${SLOT} $VEND $MODEL |" ;; esac @@ -86,37 +77,47 @@ if which smartctl > /dev/null 2>&1 ; then # trailing zeros are part of the device links in /dev/disk/by-id/... anyway # - only the last 9 chars seem to be relevant # (hopefully all this doesn't change with new kernels...) - eval `tw_cli /$TWAC show drivestatus | grep -E '^p[0-9]' | awk '{print $1 " " $7 "0"}' | while read twaminor serial ; do + eval "$(tw_cli /"$TWAC" show drivestatus | grep -E '^p[0-9]' | awk '{print $1 " " $7 "0"}' | while read -r twaminor serial ; do twaminor=${twaminor#p} serial=${serial:(-9)} serial=AMCC_${serial}00000000000 echo "$serial=$twaminor" - done` - else: + done)" + else echo "tw_cli not found" >&2 fi + INPATH_UDEVADM=$(inpath udevadm && echo "udevadm_present") + echo '<<<smart>>>' SEEN= - for D in /dev/disk/by-id/{scsi,ata}-*; do + for D in /dev/disk/by-id/{scsi,ata,nvme}-*; do [ "$D" != "${D%scsi-\*}" ] && continue [ "$D" != "${D%ata-\*}" ] && continue + [ "$D" != "${D%nvme-\*}" ] && continue [ "$D" != "${D%-part*}" ] && continue - N=$(readlink $D) + N=$(readlink "$D") N=${N##*/} - if [ -r /sys/block/$N/device/vendor ]; then - VEND=$(tr -d ' ' < /sys/block/$N/device/vendor) + if [ -r /sys/block/"$N"/device/vendor ]; then + VEND=$(tr -d ' ' < /sys/block/"$N"/device/vendor) + elif [ -r /sys/block/"$N"/device/device/vendor ]; then + VEND=NVME else # 2012-01-25 Stefan Kaerst CDJ - in case $N does not exist VEND=ATA fi - if [ -r /sys/block/$N/device/model ]; then - MODEL=$(sed -e 's/ /_/g' -e 's/_*$//g' < /sys/block/$N/device/model) + if [ -r /sys/block/"$N"/device/model ]; then + MODEL=$(sed -e 's/ /_/g' -e 's/_*$//g' < /sys/block/"$N"/device/model) else - MODEL=$(smartctl -a $D | grep -i "device model" | sed -e "s/.*:[ ]*//g" -e "s/\ /_/g") + MODEL=$(smartctl -a "$D" | grep -i "device model" | sed -e "s/.*:[ ]*//g" -e "s/\ /_/g") fi # Excluded disk models for SAN arrays or certain RAID luns that are also not usable.. - if [ "$MODEL" = "iSCSI_Disk" -o "$MODEL" = "LOGICAL_VOLUME" ]; then + if [ "$MODEL" = "iSCSI_Disk" ] || [ "$MODEL" = "LOGICAL_VOLUME" ]; then + continue + fi + + # Exclude everything which can read a CD + if [ "$INPATH_UDEVADM" == "udevadm_present" ] && (udevadm info /dev/"$N" | grep -Fxq 'E: ID_CDROM_CD=1'); then continue fi @@ -131,31 +132,41 @@ if which smartctl > /dev/null 2>&1 ; then DNAME=${DNAME#/dev/disk/by-id/ata-} # 2012-01-25 Stefan Kaerst CDJ - special option in case vendor is AMCC CMD= - if [ "$VEND" == "AMCC" -a -n "$TWAC" ]; then + if [ "$VEND" == "AMCC" ] && [ -n "$TWAC" ]; then DNAME=${DNAME#1} [ -z "${!DNAME}" ] && continue CMD="smartctl -d 3ware,${!DNAME} -v 9,raw48 -A /dev/twa0" # create nice device name including model - MODEL=$(tw_cli /$TWAC/p${!DNAME} show model | head -n 1 | awk -F= '{ print $2 }') + MODEL=$(tw_cli /"$TWAC"/p"${!DNAME}" show model | head -n 1 | awk -F= '{ print $2 }') MODEL=${MODEL## } MODEL=${MODEL// /-} DNAME=${DNAME#AMCC_} DNAME="AMCC_${MODEL}_${DNAME%000000000000}" elif [ "$VEND" != "ATA" ] ; then - TEMP= - # create temperature output as expected by checks/smart - # this is a hack, TODO: change checks/smart to support SCSI-disks - eval `smartctl -d scsi -i -A $D | while read a b c d e ; do - [ "$a" == Serial ] && echo SN=$c - [ "$a" == Current -a "$b" == Drive -a "$c" == Temperature: ] && echo TEMP=$d - done` - [ -n "$TEMP" ] && CMD="echo 194 Temperature_Celsius 0x0000 000 000 000 Old_age Always - $TEMP (0 0 0 0)" - DNAME="${VEND}_${MODEL}_${SN}" + if [ "$VEND" == "NVME" ] ; then + DNAME="/dev/$N" + CMD="smartctl -d nvme -A $DNAME" + else + TEMP= + # create temperature output as expected by checks/smart + # this is a hack, TODO: change checks/smart to support SCSI-disks + eval "$(smartctl -d scsi -i -A "$D" | while read -r a b c d _ ; do + [ "$a" == Serial ] && echo SN="$c" + [ "$a" == Current ] && [ "$b" == Drive ] && [ "$c" == Temperature: ] && echo TEMP="$d" + done)" + [ -n "$TEMP" ] && CMD="echo 194 Temperature_Celsius 0x0000 000 000 000 Old_age Always - $TEMP (0 0 0 0)" + DNAME="${VEND}_${MODEL}_${SN}" + fi else CMD="smartctl -d ata -v 9,raw48 -A $D" fi - [ -n "$CMD" ] && $CMD | grep Always | egrep -v '^190(.*)Temperature(.*)' | sed "s|^|$DNAME $VEND $MODEL |" + if [ $VEND == "NVME" ]; then + echo "$DNAME $VEND $MODEL" + [ -n "$CMD" ] && $CMD | sed -e '1,5d; /^$/d' + else + [ -n "$CMD" ] && $CMD | grep Always | grep -E -v '^190(.*)Temperature(.*)' | sed "s|^|$DNAME $VEND $MODEL |" + fi done 2>/dev/null