commit 2310741f477a7b52d552baf660cf6c9634a2a8b4 Author: Michael Höß Date: Mon Sep 28 21:18:41 2020 +0000 Add new file diff --git a/zbx-smart.ps1 b/zbx-smart.ps1 new file mode 100644 index 0000000..46d7942 --- /dev/null +++ b/zbx-smart.ps1 @@ -0,0 +1,365 @@ +# By MH 2020, MIT-License +# TODO: Logging (Sucess, Error), Windows-Support + +param ( + [switch]$smart_disco, + [switch]$smart_check, + [switch]$smart_with_external +) + + +### Misc Helper Functions + +function Get-IsUSBDrive { + param ( + [ValidateNotNullOrEmpty()] + [string]$DeviceFile + ) + + $x = lsblk -d $DeviceFile -o SUBSYSTEMS | Out-String -stream | Select-String usb + $x.Matches.Length -gt 0 +} + + +### Smart-Helper Functions + + +class SmartDev { + [String]$DeviceFile + [String]$Name + [String]$Type +} + + +# First letter lower-case for compat with zabbix-expected Json +class SmartDiscoEntry { + [String]$name + [String]$type + [String]$model + [String]$sn + [int]$rotations + [int]$lbs + [int]$isExternal + [int]$isSSD +} + + +class SmartInfoEntry { + [String]$Name + [String]$DeviceFile + [String]$Health + [int]$PowerOnHours + [int]$PowerCycleCount + [double]$Temperature +} + + +function Get-SmartDevsFromScan { + + $Res=@() + + foreach ($ln in (smartctl -n standby --scan | Out-String -stream)) { + $Obj = New-Object SmartDev + $parts=(-Split $ln) + $Obj.DeviceFile=$parts[0] + $Obj.Name=($parts[0] -Split "/")[2] + $Obj.Type=(($ln -Split ",")[1] -Split " ")[1] + $Res += $Obj + } + + return $Res +} + +function Get-SmartDisco { + + $Res = @() + + foreach ($dev in Get-SmartDevsFromScan) { + $isUSB=Get-IsUSBDrive -DeviceFile $dev.DeviceFile + + + $model = "" + + # TODO Support SSD + $isSSD=0 + if ( $isUSB -eq $False ) { + $j = smartctl -n standby -a $dev.DeviceFile --json | ConvertFrom-Json + + $model = $j.model_name + $sn = $j.serial_number + $rotrate = $j.rotation_rate + $lbs = $j.logical_block_size + } + else { + $model = $null + $sn = $null + $rotrate = $null + $lbs = $null + } + + $Obj=New-Object SmartDiscoEntry + $Obj.name=$dev.Name + $Obj.type=$dev.Type + $Obj.model=$model + $Obj.sn=$sn + $Obj.rotations=$rotrate + $Obj.lbs=$lbs + $Obj.isExternal=$isUSB ? 1 : 0 + $Obj.isSSD=$isSSD + $Res += $Obj + } + + + return $Res +} + + + +function Get-SmartInfo { + param ( + [Parameter(Mandatory=$true)] + [SmartDev]$device + ) + + $Res = New-Object SmartInfoEntry + $Res.DeviceFile = $device.DeviceFile + $Res.Name = $device.Name + + smartctl -s on $device.DeviceFile | out-null + + $st=$(smartctl -n standby -q errorsonly -H $device.DeviceFile) + + if ( $st.Trim.Length -eq 0 ) { + $st = "OK" + } + + + $j=smartctl -n standby -a $device.DeviceFile --json | ConvertFrom-Json + + $Res.Health = $st + $Res.PowerOnHours = $j.power_on_time.hours + $Res.PowerCycleCount = $j.power_cycle_count + $Res.Temperature = $j.temperature.current + + return $Res +} + + +function Get-SmartInfos { + + param ( + [bool]$withExternalDevs + ) + + $Res = @() + + foreach ($dev in Get-SmartDevsFromScan) { + $isUSB=Get-IsUSBDrive -DeviceFile $dev.DeviceFile + + if ( $isUSB -And -Not $withExternalDevs ) { + continue + } + + smartctl -s on $dev.DeviceFile | out-null + + $si = Get-SmartInfo -device $dev + $Res += $si + } + + return $Res +} + + +### Monitoring functions + +function Send-SmartDiscoToZabbix { + $disco = Get-SmartDisco + + $jsons=$disco | ConvertTo-Json -Compress + zabbix_sender -vv -k "8o_smartcheck.disco_devs" -o '$jsons' -c /etc/zabbix/zabbix_agentd.conf +} + + +function Send-SmartInfosToZabbix { + + param ( + [bool]$withExternalDevs + ) + + &{ + foreach( $dev in Get-SmartInfos -withExternalDevs $withExternalDevs ) { + # Better solution? + $dn = $dev.Name + Write-Output "- 8o_smartcheck.[${dn}.health] $($dev.Health)" + Write-Output "- 8o_smartcheck.[${dn}.power_on_hours] $($dev.PowerOnHours)" + Write-Output "- 8o_smartcheck.[${dn}.power_cycle_count] $($dev.PowerCycleCount)" + Write-Output "- 8o_smartcheck.[${dn}.temperature] $($dev.Temperature)" + } + } | zabbix_sender -vv -i - -c /etc/zabbix/zabbix_agentd.conf +} + + +$exitcode=0 + +if ( $smart_disco ) { + Write-Output "Doing SMART-Disco " + Send-SmartDiscoToZabbix +} + +if ( $smart_check ) { + Write-Output "Doing SMART-Check withExternal: ${smart_with_external} " + Send-SmartInfosToZabbix -withExternalDevs $smart_with_external +} + +Write-Output "Done" + +exit $exitcode + +and here is the original Bash-version: + +#!/bin/bash + +# By MH 2020, MIT-License + + +_smart_is_usb() +{ + rem=$(lsblk -d "$1" -o SUBSYSTEMS | grep "usb" | wc -l) + if [[ "${rem}" == "0" ]]; then + echo 0 + else + echo 1 + fi +} + +_smart_getval() +{ + echo -e "$1" | grep -i "^${2} = " | cut -d "=" -f 2 | cut -d '"' -f 2 +} + +_smart_getval_i() +{ + res=$(echo -e "$1" | grep -i "^${2} = " | cut -d "=" -f 2 | cut -d ' ' -f 2 | tr -d ";") + if [[ "$res" == "" ]]; then + res=0 + fi + echo "${res}" +} + + +smart_disco() { + c=0 + devs="" + while read ln; do + dev=$(echo ${ln} | cut -d " " -f 1 | sed -e "s/\/dev\///g") + typ=$(echo ${ln} | cut -d " " -f 3) + + + # Removable + # rem=$(lsblk -d /dev/${dev} -o SUBSYSTEMS | grep "usb" | wc -l) + rem=$(_smart_is_usb "/dev/${dev}") + + if [[ "${rem}" == "0" ]]; then + smart="$(smartctl -n standby -a /dev/${dev} --json=g)" + model="$(_smart_getval "${smart}" "json.model_name")" + sn="$(_smart_getval "${smart}" "json.serial_number")" + rot="$(_smart_getval_i "${smart}" "json.rotation_rate")" + lbs="$(_smart_getval_i "${smart}" "json.logical_block_size")" + + #SSD: TODO + isSSD=0 + fi + + if (( c == 1 )); then + devs="${devs},\n" + fi + c=1 + + devs="${devs} {\n" + + if [[ "${rem}" == "0" ]]; then + devs="${devs} \"name\": \"${dev}\",\n" + devs="${devs} \"type\": \"${typ}\",\n" + devs="${devs} \"model\": \"${model}\",\n" + devs="${devs} \"sn\": \"${sn}\",\n" + devs="${devs} \"rotations\": ${rot},\n" + devs="${devs} \"lbs\": ${lbs},\n" + devs="${devs} \"isExternal\": ${rem},\n" + devs="${devs} \"isSSD\": ${isSSD}\n" + else + devs="${devs} \"name\": \"${dev}\",\n" + devs="${devs} \"isExternal\": ${rem}\n" + fi + devs="${devs} }" + + done < <(smartctl -n standby --scan) + + + + json2="\n{" + json2="${json2} \"devices\": [\n" + json2="${json2} ${devs}\n" + json2="${json2} ]\n" + json2="${json2}}" + echo -e "$json2" + + # Remove newline for use as parameter + sentval="$(echo -e $json2)" + + #json=$(smartctl --json --scan) + #json=$(echo "${json}" | sed -e "s/\/dev\///g") + #echo $json + + zabbix_sender -vv -k "8o_smartcheck.disco_devs" -o "${sentval}" -c /etc/zabbix/zabbix_agentd.conf 2>&1 | logger -t "zabbix-smart_disco" +} + + +smart_check() { + (for dev in $(smartctl --scan | sed -e "s/\/dev\///g" | cut -d " " -f 1 ); do + + rem=$(_smart_is_usb "/dev/${dev}") + if [[ "${rem}" == "1" ]] && [[ "${SMART_WITH_EXTERNAL}" == "0" ]]; then + #echo "X" 1>&2 + continue; + fi + + smartctl -s on /dev/${dev} > /dev/null + status="$(smartctl -n standby -q errorsonly -H /dev/${dev})" + if [[ "${status}" == "" ]]; then + status="OK" + fi + + smart="$(smartctl -n standby -a /dev/${dev} --json=g)" + + poh="$(_smart_getval_i "${smart}" "json.power_on_time.hours")" + poc="$(_smart_getval_i "${smart}" "json.power_cycle_count")" + temp="$(_smart_getval_i "${smart}" "json.temperature.current")" + + + + #zabbix_sender -vv -k "8o_smartcheck.[${dev}.health]" -o "${status}" -c /etc/zabbix/zabbix_agentd.conf \ + # 2>&1 | logger -t "zabbix-smart_health" + + echo "- 8o_smartcheck.[${dev}.health] ${status}" + echo "- 8o_smartcheck.[${dev}.power_on_hours] ${poh}" + echo "- 8o_smartcheck.[${dev}.power_cycle_count] ${poc}" + echo "- 8o_smartcheck.[${dev}.temperature] ${temp}" + + #echo "8o_smartcheck.[${dev}.health]" + #echo ${dev} + done) | zabbix_sender -vv -i - -c /etc/zabbix/zabbix_agentd.conf 2>&1 | logger -t "zabbix-smart_health" + +} + + +SMART_WITH_EXTERNAL=0 + +if [ "$1" == "--smart-with-external" ]; then + SMART_WITH_EXTERNAL=1 +fi + +if [ "$1" == "--disco" ]; then + smart_disco +else + smart_check +fi \ No newline at end of file