#!/bin/bash

################
#
# Author: Dimitri Enns @ Timme Hosting
# Date : 2021-05-21
# Version : 0.1
#
################
if [[ ! -x $(which lscpu) ]]; then
	echo "lscpu is not installed here."
	exit 1
fi

if [[ ! -x $(which sensors) ]]; then
	echo "sensors is not installed here."
	exit 1
fi

if [[ ! -x $(which uname) ]]; then
	echo "uname is not installed here."
	exit 1
fi

CPUS=$(nproc)
CPU_VENDOR=$(lscpu | grep 'Vendor ID:')
VZ_KERNEL=$(uname -r | grep 'openvz' | wc -l)
HEAT_STATE="LOW"
LOAD=$(awk '{printf "%3.0f\n" ,$1}' /proc/loadavg)

if [[ -z ${CPU_VENDOR} || -z ${VZ_KERNEL} ]]; then
	echo "Not able to find CPU Vendor ID or Kernel Version."
	exit 1
fi
function check_heat() {
	if [[ ${CPU_VENDOR} =~ 'GenuineIntel' ]]; then
		## Intel Platform
		if [[ -r "/sys/devices/platform/coretemp.0/temp1_label" && $(cat /sys/devices/platform/coretemp.0/temp1_label) == "Physical id 0" ]]; then
			if [[  -r "/sys/devices/platform/coretemp.0/temp1_max" && -r "/sys/devices/platform/coretemp.0/temp1_input" && -r "/sys/devices/platform/coretemp.0/temp1_crit" ]]; then
				export MAX_HEAT=$(($(cat /sys/devices/platform/coretemp.0/temp1_max) / 1000))
				export CUR_HEAT=$(($(cat /sys/devices/platform/coretemp.0/temp1_input) /1000))
				export CRIT_HEAT=$(($(cat /sys/devices/platform/coretemp.0/temp1_crit) /1000))
				if [[ ${CUR_HEAT} -ge ${CRIT_HEAT} ]]; then
					export HEAT_STATE="VHIGH"
				elif [[ ${CUR_HEAT} -ge ${MAX_HEAT} && ${CUR_HEAT} -lt ${CRIT_HEAT} ]]; then
					export HEAT_STATE="HIGH"
				fi
			fi
		elif [[ ! -r "/sys/devices/platform/coretemp.0/temp1_label" ]]; then
			export HEAT_STATE="NA"
		fi
	elif [[ ${CPU_VENDOR} =~ 'AuthenticAMD' ]]; then
		## AMD Platform on KVM Machines
		
		MAX_HEAT_FILE=$(find /sys/devices/ -iname "temp1_input" | grep -E 'pci(.*)hwmon0')
		CUR_HEAT_FILE=$(find /sys/devices/ -iname "temp2_input" | grep -E 'pci(.*)hwmon0')

		if [[ ! -z ${MAX_HEAT_FILE} && ! -z ${CUR_HEAT_FILE} ]]; then
			export MAX_HEAT=$(($(cat ${MAX_HEAT_FILE}) /1000 ))
			export CUR_HEAT=$(($(cat ${CUR_HEAT_FILE}) /1000 ))
			if [[ ${CUR_HEAT} -ge ${MAX_HEAT} ]]; then
				export HEAT_STATE="VHIGH"
			fi
		elif [[ -z ${MAX_HEAT_FILE} || -z ${CUR_HEAT_FILE} ]]; then
			export HEAT_STATE="NA"
		fi
	fi
}


if [[ -f "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq" ]]; then
	CPU_MIN="$(($(cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq) / 1000))"
else
	echo "Not able to find cpuinfo_min_freq file."
	exit 2
fi

if [[ (${CPU_VENDOR} =~ 'GenuineIntel' && ${VZ_KERNEL} == "1") || (${CPU_VENDOR} =~ 'AuthenticAMD' && ${VZ_KERNEL} == "0") ]]; then
	if [[ ${LOAD} -gt "1" ]]; then
		check_heat
		MHZSUM=$(($(for i in $(find /sys/devices/system/cpu/ -iname "scaling_cur_freq" -type f); do cat $i; done | awk '{sum += $1} END {print sum}')/ 1000))
		RESULT=$((${MHZSUM} / ${CPUS}))
		if [[ ${RESULT} -le ${CPU_MIN} ]]; then
			while [[ ${RESULT} -le ${CPU_MIN} ]]; do
				LOAD=$(awk '{printf "%3.0f\n" ,$1}' /proc/loadavg)
				check_heat
				COUNTER=$((COUNTER+1))
				sleep 1
				MHZSUM=$(($(for i in $(find /sys/devices/system/cpu/ -iname "scaling_cur_freq" -type f); do cat $i; done | awk '{sum += $1} END {print sum}')/ 1000))
				RESULT=$((${MHZSUM} / ${CPUS}))
				MESSAGE="CPU CLOCK AVG @ ${RESULT}MHz"
				[[ ${HEAT_STATE} == "VHIGH" ]] && MESSAGE+=" ${CUR_HEAT}°C"
				echo "${MESSAGE}"
				if [[ ${COUNTER} == "30" ]]; then
					MHZSUM=$(($(for i in $(find /sys/devices/system/cpu/ -iname "scaling_cur_freq" -type f); do cat $i; done | awk '{sum += $1} END {print sum}')/ 1000))
					RESULT=$((${MHZSUM} / ${CPUS}))
					if [[ ${CPU_VENDOR} =~ 'GenuineIntel' ]]; then
						if [[ ${RESULT} -le ${CPU_MIN} ]]; then
							MESSAGE="CRIT: CPU AVERAGE STUCK @ ${RESULT}MHz"
							[[ ${HEAT_STATE} == "VHIGH" ]] && MESSAGE+=" + HIGH TEMP: ${CUR_HEAT}°C"
							echo "${MESSAGE}"
							exit 2
						fi
					elif [[ ${CPU_VENDOR} =~ 'AuthenticAMD' ]]; then
						if [[ ${RESULT} -le ${CPU_MIN} && ${LOAD} -gt $((${CPUS}/2)) ]]; then
							MESSAGE="CRIT: CPU AVERAGE STUCK @ ${RESULT}MHz"
							[[ ${HEAT_STATE} == "VHIGH" ]] && MESSAGE+=" + HIGH TEMP: ${CUR_HEAT}°C"
							echo "${MESSAGE}"
							exit 2
						fi
					fi
				fi
			done
		else
			echo "CPU avg @ ${RESULT}MHz. ${CUR_HEAT}°C"
			exit 0
		fi
	else
		echo "No need for a check. 5 minutes load average is below 1.5"
		exit 0
	fi
elif [[ ${CPU_VENDOR} =~ 'AuthenticAMD' && ${VZ_KERNEL} == "1" ]]; then
	echo "AMD CPU on a OpenVZ Kernel detected."
	exit 0
fi
