#!/bin/bash

usage() {
	echo "Usage: ./check_snmp_synologyV2 -H hostname -t test [-C community] [-w warnLowTempC:warnHighTempC] [-c critLowTempC:critHighTempC] [-r SNMPretries] [-T SNMPtimeout] [-v]"
	exit 3
}

if [ $# -eq 0 ]; then
	usage
fi

baseOID="1.3.6.1.4.1.6574"
systemOID="$baseOID.1"
diskOID="$baseOID.2"
raidOID="$baseOID.3"
smartOID="$baseOID.5"

# System Status
sysStat=0
sysStatOID="$systemOID.1"

# System Temperature
sysTemp=0
sysTempOID="$systemOID.2"

# System Power 
sysPower=0
sysPowerOID="$systemOID.3"

# System Fan Status
sysFan=0
sysFanOID="$systemOID.4.1"

# CPU Fan Status
cpuFan=0
cpuFanOID="$systemOID.4.2"

# Other variables
check=""
checkList="System DiskStatus DiskTemp RAID"
checkListLower=$(echo $checkList | awk '{print tolower($0)}')
outString=""
textString=""
dataString=""
returnStat=0
community="public" # Public by default
tempWarn="7:40" # 7:40 by default
tempCrit="1:50" # 0: 50 by default
verbose=0
retries=5
timeout=1

while getopts ":C:H:w:c:t:r:T:v" opt ; do
	case $opt in
		C)
			community="$OPTARG"
			;;
		H)
			HSTNAME="$OPTARG"
			;;
		w)
			tempWarn="$OPTARG"
			;;
		c)
			tempCrit="$OPTARG"
			;;
		t)
			check="$OPTARG"
			;;
		r)
			retries="$OPTARG"
			;;
		T)
			timeout="$OPTARG"
			;;
		v)
			verbose=1
			;;
		*)
			usage
			;;
	esac
done

check=$(echo $check | awk '{print tolower($0)}')

# SNMP shorthand
function snmp {
	echo $(snmpwalk -c $community -v1 -r $retries -t $timeout -Ovq $HSTNAME $1)
}
# Convert C to F
function ctof {
    echo $(echo "scale=1; ($1*(9/5)) + 32" | bc -l)
}
function vout {
	if [ $verbose -eq 1 ] ; then echo "$1" ; fi
}

if ! [[ $HSTNAME ]] ; then
	echo "[UNKNOWN] - No target hostname provided."
	exit 3
elif ! $(echo $checkListLower | grep -qw $check); then
	echo "[UNKNOWN] - Invalid check specified. Check specified $check. Valid selection: $checkList (not case-sensitive)"
	exit 3
fi

# Check list:
# System Status
# Disk Status
# Raid Status

if [[ $check == "system" ]] ; then
	# System Status
	sysStat=$(snmp $sysStatOID)
	if (($sysStat == 2)) ; then
		textString+="[CRITICAL] - System failure. : "
		returnStat=3
	elif (($sysStat == 1)) ; then
		textString+="System Self-Status OK : "
	else 
		textString+="[UNKNOWN] - OID not found : "
		returnStat=$(($returnStat>2 ? $returnStat : 2))
	fi

	# System Temperature
	sysTemp=$(snmp $sysTempOID)
	critLow=$(echo $tempCrit | cut -d':' -f1)
	warnLow=$(echo $tempWarn | cut -d':' -f1)
	warnHigh=$(echo $tempWarn | cut -d':' -f2)
	critHigh=$(echo $tempCrit | cut -d':' -f2)
	vout "sysTempC: $sysTemp critLowC: $critLow warnLowC: $warnLow warnHighC: $warnHigh critHighC: $critHigh"

	# Values in F for Display
	sysTempD=$(ctof $sysTemp)
	critLowD=$(ctof $critLow)
	warnLowD=$(ctof $warnLow)
	warnHighD=$(ctof $warnHigh)
	critHighD=$(ctof $critHigh)
	vout "sysTempF: $sysTempD critLowF: $critLowD warnLowF: $warnLowD warnHighF: $warnHighD critHighF: $critHighD"


	if (($sysTemp >= $warnLow)) && (($sysTemp <= $warnHigh)) ; then
		textString+="System temperature [OK] ${sysTempD}F."
	elif (($sysTemp < $critLow)) || (($sysTemp > $critHigh)) ; then
		textString+="[CRITICAL] - System temperature critical ${sysTempD}F. Critical range $critLowD to $critHighD."
		returnStat=3
	elif (($sysTemp <= $warnLow)) || (($sysTemp >= $warnHigh)) ; then
		textString+="[WARNING] - System temperature approaching critical levels ${sysTempD}F. Critical range $critLowD to $critHighD. Warning range $warnLowD to $warnHighD."
		returnStat=$(($returnStat>1 ? $returnStat : 1))
	else
		textString+="[UNKNOWN] - An invalid value was returned for system temperature. Value ${sysTemp}C."
		returnStat=$(($returnStat>2 ? $returnStat : 2))
	fi
	dataString+="sys_tempC=$sysTemp;$tempWarn;$tempCrit; "
	textString+=" : "

	# System Power 
	sysPower=$(snmp $sysPowerOID)
	if (($sysPower == 1)) ; then
		textString+="Power supply status OK."
	elif (($sysPower == 2)) ; then
		textString+="[CRITICAL] - Power supply failed."
		returnStat=3
	else
		textString+="[UNKNOWN] - Device returned invalid PSU status $sysPower."
		returnStat=$(($returnStat>2 ? $returnStat : 2))
	fi
	textString+=" : "

	# System Fan Status
	sysFan=$(snmp $sysFanOID)
	if (($sysFan == 1)) ; then
		textString+="Sys fan status OK."
	elif (($sysFan == 2)) ; then
		textString+="[CRITICAL] - Sys fan failed."
		returnStat=3
	else
		textString+="[UNKNOWN] - Device returned invalid sys fan status $sysFan."
		returnStat=$(($returnStat>2 ? $returnStat : 2))
	fi
	textString+=" : "

	# CPU Fan Status
	cpuFan=$(snmp $cpuFanOID)
	if (($cpuFan == 1)) ; then
		textString+="CPU fan status [OK]."
	elif (($cpuFan == 2)) ; then
		textString+="[CRITICAL] - CPU fan failed."
		returnStat=3
	else
		textString+="[UNKNOWN] - Device returned invalid CPU fan status $cpuFan."
		returnStat=$(($returnStat>2 ? $returnStat : 2))
	fi

	case $returnStat in
	0)
		outString+="[OK] - Overall system health OK. "
		;;
	1)
		outString+="[WARNING] - Overall system health outside normal parameters. "
		;;
	2)
		outString+="[UNKNOWN] - An invalid value was returned for one or more checks. "
		returnStat=3
		;;
	3)
		outString+="[CRITICAL] - System requires attention for one or more issues. "
		returnStat=2
		;;
	*)
		outString+="[UNKNOWN] - Script returned an invalid return status. "
		returnStat=3
		;;
esac
fi

if [[ $check == "diskstatus" ]] ; then
	diskCount=$(snmp $diskOID.1.1.5 | wc -l)
	i=0
	while (($i < $diskCount)) ; do
		diskResult=$(snmp $diskOID.1.1.5.$i 2>&1)
        if [[ $diskResult == *"Timeout"* ]] || [[ $diskResult == *"timeout"* ]]; then
            echo "[UNKNOWN] - Timeout when querying $HSTNAME"
            exit 3
        fi
		vout "disk $i result: $diskResult"
		case $diskResult in
			0)
				:
				;;
			1)
				textString+="D$(($i+1)) [OK]"
				;;
			2)
				textString+="D$(($i+1)) W Empty"
				returnStat=$(($returnStat>1 ? $returnStat : 1))
				;;
			3)
				textString+="D$(($i+1)) W Non-Init"
				returnStat=$(($returnStat>1 ? $returnStat : 1))
				;;
			4)
				textString+="D$(($i+1)) C Damaged"
				returnStat=3
				;;
			5)
				textString+="D$(($i+1)) C Crashed"
				returnStat=3
				;;
			*)
				textString+="D$(($i+1)) [UNKNOWN] $diskResult"
				returnStat=$(($returnStat>2 ? $returnStat : 2))
				;;
		esac
		i=$(($i+1))
		if (($i < $diskCount)) ; then
			textString+=" : "
		fi
	done

	case $returnStat in
	0)
		outString+="[OK] - Overall disk health OK. "
		;;
	1)
		outString+="[WARNING] - Overall disk health outside normal parameters. "
		;;
	2)
		outString+="[UNKNOWN] - Invalid value returned for 1+ checks. "
		returnStat=3
		;;
	3)
		outString+="[CRITICAL] - 1+ disks requires immediate attention. "
		returnStat=2
		;;
	*)
		outString+="[UNKNOWN] - Script returned an invalid return status. "
		returnStat=3
		;;
esac
fi

if [[ $check == "disktemp" ]] ; then
	result=$(snmp $diskOID.1.1.6 2>/dev/null)
	diskCount=$(echo "$result" | wc -l)
	i=0
	critLow=$(echo $tempCrit | cut -d':' -f1)
	warnLow=$(echo $tempWarn | cut -d':' -f1)
	warnHigh=$(echo $tempWarn | cut -d':' -f2)
	critHigh=$(echo $tempCrit | cut -d':' -f2)
	vout "critLowC: $critLow warnLowC: $warnLow warnHighC: $warnHigh critHighC: $critHigh"

	# Values in F for Display
	critLowD=$(ctof $critLow)
	warnLowD=$(ctof $warnLow)
	warnHighD=$(ctof $warnHigh)
	critHighD=$(ctof $critHigh)
	vout "critLowF: $critLowD warnLowF: $warnLowD warnHighF: $warnHighD critHighF: $critHighD"

	if [ "$result" = "" ]; then
		echo "[UNKNOWN] - Check returned 0 or fewer disks."
		exit 3
	fi

	textString+="Critical range ${critLowD}F to ${critHighD}F. Warn range ${warnLowD}F to ${warnHighD}F. "
	for j in $result; do
		diskResultD=$(ctof $i)
		if (($j >= $warnLow)) && (($j <= $warnHigh)) ; then
			textString+="D$(($i+1)) [OK] ${diskResultD}F"
		elif (($j < $critLow)) || (($j > $critHigh)) ; then
			textString+="D$(($i+1)) C ${diskResultD}F"
			returnStat=3
		elif (($j <= $warnLow)) || (($j >= $warnHigh)) ; then
			textString+="D$(($i+1)) W ${diskResultD}F"
			returnStat=$(($returnStat>1 ? $returnStat : 1))
		else
			textString+="D$(($i+1)) U ${diskResult}C"
			returnStat=$(($returnStat>2 ? $returnStat : 2))
		fi
		dataString+="disk${i}_tempC=$j;$tempWarn;$tempCrit; "
		if (($i < $diskCount)) ; then
			textString+=" : "
		fi
		i=$(($i+1))
	done

	case $returnStat in
	0)
		outString+="[OK] - Disk temp status OK. "
		;;
	1)
		outString+="[WARNING] - 1+ disk temps outside normal range. "
		;;
	2)
		outString+="[UNKNOWN] - Invalid value returned for 1+ checks. "
		returnStat=3
		;;
	3)
		outString+="[CRITICAL] - 1+ disk temps critical. "
		returnStat=2
		;;
	*)
		outString+="[UNKNOWN] - Script returned an invalid return status. "
		returnStat=3
		;;
esac
fi

if [[ $check == "raid" ]] ; then
	raidCount=$(snmp $raidOID.1.1.2 | wc -l)
	i=0
	while (($i < $raidCount)) ; do
		name=$(snmp $raidOID.1.1.2.$i)
        result=$(snmp $raidOID.1.1.3.$i 2>&1)
        echo vout "result: $result"
        if [[ $result == *"Timeout"* ]] || [[ $result == *"timeout"* ]] ; then
			echo "[UNKNOWN] - Timeout when querying $HSTNAME"
            exit 3
		fi
		vout "raid $i result: name $name result $result"
		case $result in
			1)
				textString+="[OK]: RAID $name OK."
				;;
			2)
				textString+="[CRITICAL]: RAID $name is repairing."
				returnStat=3
				;;
			3)
				textString+="[WARNING]: RAID $name is migrating."
				returnStat=$(($returnStat>1 ? $returnStat : 1))
				;;
			4)
				textString+="[WARNING]: RAID $name is expanding."
				returnStat=$(($returnStat>1 ? $returnStat : 1))
				;;
			5)
				textString+="[WARNING]: RAID $name is deleting."
				returnStat=$(($returnStat>1 ? $returnStat : 1))
				;;
			6)
				textString+="[WARNING]: RAID $name is creating."
				returnStat=$(($returnStat>1 ? $returnStat : 1))
				;;
			7)
				textString+="[WARNING]: RAID $name is syncing."
				returnStat=$(($returnStat>1 ? $returnStat : 1))
				;;
			8)
				textString+="[WARNING]: RAID $name is parity checking."
				returnStat=$(($returnStat>1 ? $returnStat : 1))
				;;
			9)
				textString+="[WARNING]: RAID $name is assembling."
				returnStat=$(($returnStat>1 ? $returnStat : 1))
				;;
			10)
				textString+="[WARNING]: RAID $name is canceling."
				returnStat=$(($returnStat>1 ? $returnStat : 1))
				;;
			11)
				textString+="[CRITICAL]: RAID $name is degraded."
				returnStat=3
				;;
			12)
				textString+="[CRITICAL]: RAID $name has crashed."
				returnStat=3
				;;
			13)
				textString+="[OK]: Raid $name data scrubbing."
				;;
			14)
				textString+="[WARNING]: Raid $name is deploying."
				returnStat=$(($returnStat>1 ? $returnStat : 1))
				;;	
			*)
				textString+="[UNKNOWN]: RAID $name status unknown $result."
				returnStat=$(($returnStat>2 ? $returnStat : 2))
				;;
		esac
		i=$(($i+1))
		if (($i < $raidCount)) ; then
			textString+=" - "
		fi
	done

	case $returnStat in
	0)
		outString+="[OK] - Overall RAID health OK. -- "
		;;
	1)
		outString+="[WARNING] - Overall RAID health outside normal parameters. "
		;;
	2)
		outString+="[UNKNOWN] - An invalid value was returned for one or more checks. "
		returnStat=3
		;;
	3)
		outString+="[CRITICAL] - One or more RAIDs require immediate attention. "
		returnStat=2
		;;
	*)
		outString+="[UNKNOWN] - Script returned an invalid return status. "
		returnStat=3
		;;
esac
fi

outString+=$textString
if [[ $dataString ]] ; then
	outString+="|"
	outString+=$dataString
fi
echo $outString
exit $returnStat
