|
@@ -0,0 +1,123 @@
|
|
|
+#!/bin/sh
|
|
|
+
|
|
|
+# {{{ Variables
|
|
|
+DEVICE=
|
|
|
+ATTRIBUTE=
|
|
|
+SCAN=0
|
|
|
+ZBX_DISCOVERY_OUTPUT=0
|
|
|
+# }}}
|
|
|
+
|
|
|
+# {{{ usage()
|
|
|
+usage() {
|
|
|
+cat <<EOH
|
|
|
+USAGE: $(basename "$0") -d DEVICE -a ATTRIBUTE
|
|
|
+
|
|
|
+Get SMART attribute value for a NVMe device
|
|
|
+
|
|
|
+Options:
|
|
|
+ -d NVMe device path
|
|
|
+ -a Attribute name (e.g: temperature, program_fail_count, etc.)
|
|
|
+ -S Scan devices and display list
|
|
|
+ -s Scan devices and display (Zabbix discovery output)
|
|
|
+EOH
|
|
|
+}
|
|
|
+# }}}
|
|
|
+
|
|
|
+# {{{ list_nvme_devices()
|
|
|
+list_nvme_devices() {
|
|
|
+ ZBX="${1}"
|
|
|
+ if [ "${ZBX}" = 1 ]; then
|
|
|
+ printf '{"data":['
|
|
|
+ fi
|
|
|
+ if which nvme >/dev/null 2>&1 && which jq >/dev/null 2>&1 ; then
|
|
|
+ (
|
|
|
+ nvme list --output json | \
|
|
|
+ jq --raw-output \
|
|
|
+ '.Devices | .[] | .DevicePath + " " + .SerialNumber + " " + (.PhysicalSize|tostring) + " NVMe"' | \
|
|
|
+ while read device serial physsize hwinfo ; do
|
|
|
+ if which numfmt >/dev/null 2>&1 ; then
|
|
|
+ capacity=$(numfmt --to=si --suffix=B --round=nearest --format="%2f" 1920383410176|sed -r 's/([a-z]+)/ \1/i')
|
|
|
+ else
|
|
|
+ capacity="$(( ${physsize} / 1000 / 1000 / 1000 )) GB"
|
|
|
+ fi
|
|
|
+ if [ "${ZBX}" = 1 ]; then
|
|
|
+ printf '{'
|
|
|
+ printf '"{#DEVICE}":"%s",' "${device}"
|
|
|
+ printf '"{#SERIAL}":"%s",' "${serial}"
|
|
|
+ printf '"{#CAPACITY}":"%s",' "${capacity}"
|
|
|
+ printf '"{#HWROT}":"%s"' "${hwinfo}"
|
|
|
+ printf '},'
|
|
|
+ else
|
|
|
+ echo "${device}|${serial}|${capacity}|${hwinfo}"
|
|
|
+ fi
|
|
|
+ done
|
|
|
+ ) | sed 's/},$/}/'
|
|
|
+ fi
|
|
|
+ if [ "${ZBX}" = 1 ]; then
|
|
|
+ printf ']}'
|
|
|
+ fi
|
|
|
+}
|
|
|
+# }}}
|
|
|
+
|
|
|
+# {{{ main()
|
|
|
+while getopts "d:a:Ss" OPT ; do
|
|
|
+ case "$OPT" in
|
|
|
+ \?|h)
|
|
|
+ usage
|
|
|
+ exit 0
|
|
|
+ ;;
|
|
|
+ d)
|
|
|
+ DEVICE="$OPTARG"
|
|
|
+ ;;
|
|
|
+ a)
|
|
|
+ ATTRIBUTE="$OPTARG"
|
|
|
+ ;;
|
|
|
+ S)
|
|
|
+ SCAN=1
|
|
|
+ ;;
|
|
|
+ s)
|
|
|
+ SCAN=1
|
|
|
+ ZBX_DISCOVERY_OUTPUT=1
|
|
|
+ ;;
|
|
|
+ esac
|
|
|
+done
|
|
|
+
|
|
|
+if [ "${SCAN}" = 1 ]; then
|
|
|
+ list_nvme_devices "${ZBX_DISCOVERY_OUTPUT}"
|
|
|
+ exit 0
|
|
|
+fi
|
|
|
+
|
|
|
+if [ -z "${DEVICE}" ] ; then
|
|
|
+ printf "[ERR] device is not defined\n"
|
|
|
+ usage
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+if [ -z "${ATTRIBUTE}" ] ; then
|
|
|
+ printf "[ERR] attribute name is not defined\n"
|
|
|
+ usage
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+if [ "${ATTRIBUTE}" = "error_count" ]; then
|
|
|
+ data=$(nvme error-log "${DEVICE}" --output json | jq '.[][-1] | .error_count')
|
|
|
+else
|
|
|
+ data=$(nvme smart-log --output json "${DEVICE}" | jq --raw-output ".${ATTRIBUTE}")
|
|
|
+ if [ "${ATTRIBUTE}" = "temperature" ]; then
|
|
|
+ data=$(( ${data} - 273 )) # convert into Celcius 'temperature' value (Kelvin in JSON output)
|
|
|
+ fi
|
|
|
+fi
|
|
|
+
|
|
|
+if [ $? != 0 ] || [ "${data}" = "null" ]; then
|
|
|
+ printf -- "-1\n"
|
|
|
+else
|
|
|
+ printf "${data}\n" | \
|
|
|
+ tr -s ' ' | \
|
|
|
+ sed 's/^[[:space:]]*\(.*\)[[:space:]]*$/\1/' | \
|
|
|
+ cut -d ' ' -f 10
|
|
|
+fi
|
|
|
+
|
|
|
+exit 0
|
|
|
+# }}}
|
|
|
+
|
|
|
+# vim: foldmethod=marker foldlevel=0 foldenable
|