I have / had a problem of servers in my rack overheating. The permanent solution is of course to make the effort to get the portable air conditioner out of my storage unit and set it up in my computer room [box room]. However, that requires a bunch of physical effort.
The short term solution is to get my Zabbix monitoring server to turn on a an 18" floor standing fan whenever the ambient temperature inside the rack is substantially higher than the ambient temperature of the room, or when disk temperatures exceed 40C.
...so welcome to temporary janky solution number 1...
Zabbix has a trigger action which will touch /tmp/fan.on
whenever the prerequisite temperature conditions occur.
A script run out of the crontab then takes care of the rest.
*/3 * * * * /home/nicolaw/bin/fan.cron 2>&1 | tee -a /tmp/fan.cron.log
#!/bin/bash
set -uE -o pipefail
ACTION_FILE="/tmp/fan"
STATE_LOG="/tmp/fan.log"
STALE_SECS=3600
FAN_CMD="/home/nicolaw/bin/fan"
last_known_state() {
if grep -A 99 "Command successfully issued." "$STATE_LOG" 2>/dev/null \
| grep -qo "State\s*:\s*ON" ; then
echo "on"
elif grep -A 99 "Command successfully issued." "$STATE_LOG" 2>/dev/null \
| grep -qo "State\s*:\s*OFF" ; then
echo "off"
else
echo "UNKNOWN"
return 1
fi
return 0
}
is_integer() {
local str="$1"
if [[ "$str" =~ ^[0-9]+$ ]] ; then
return 0
fi
return 1
}
file_age() {
local file="$1"
local now="$(date +%s)"
local mtime="$(stat -c %Y "$file" 2>/dev/null)"
is_integer "$mtime" || mtime="-1"
if is_integer "$now" ; then
echo "$(( now - mtime ))"
return 0
fi
return 1
}
is_stale() {
local file="$1"
local maxage="${2:-$STALE_SECS}"
local fileage="$(file_age "$file")"
if [[ $fileage -ge $maxage ]] ; then
return 0
fi
return 1
}
fan_toggle() {
local action="$1"
local reason="${2:-}"
echo -n "$(date +"%Y-%m-%d %H:%M:%S%z") Turning fan $action ${reason:+($reason) }..."
$FAN_CMD $action > "$STATE_LOG" 2>&1
if [[ "$(last_known_state)" == "$action" ]] ; then
echo " DONE"
return 0
fi
echo " FAILED"
return 1
}
# Remove stale instructions
for file in $ACTION_FILE.{on,off} ; do
[[ -e "$file" ]] && is_stale "$file" && rm -f "$file"
done
# Determine our action
ACTION=""
if [[ -e "${ACTION_FILE}.off" ]] || [[ -e "${ACTION_FILE}.on" ]] ; then
ACTION="off"
if [[ $(file_age "${ACTION_FILE}.on") -lt $(file_age "${ACTION_FILE}.off") ]] ; then
ACTION="on"
fi
fi
# Perform explicit action
if [[ -n "$ACTION" ]] ; then
fan_toggle $ACTION "$(cat "${ACTION_FILE}.$ACTION")"; rc=$?
[[ $rc -eq 0 ]] && rm -f "${ACTION_FILE}".{on,off}
exit $rc
# State log is stale and fan probably still on; turn the fan off
elif [[ -e "$STATE_LOG" ]] && is_stale "$STATE_LOG" && \
[[ "$(last_known_state)" == "on" ]] ; then
fan_toggle off "$STALE_SECS timeout reached"
exit $?
# Nothing to do
else
exit 0
fi
exit 1
#!/usr/bin/expect
set timeout 60
if {[llength $argv] != 1} {
send_user "Usage: fan <on|off> \n"
exit 1
}
set onoff [lindex $argv 0]
set username "my_username"
set password "my_password"
set hostname "pdu.hostname.fqdn"
set outlet "1"
set offstring "off"
set state "1"
if { [string compare $onoff $offstring] == 0 } {
set state "2"
}
spawn ssh -p 22 -4 -o PreferredAuthentications=password -o PasswordAuthentication=yes -o Ciphers=aes128-cbc,aes256-cbc,3des-cbc,blowfish-cbc -o MACs=hmac-sha1,hmac-md5 -o KexAlgorithms=diffie-hellman-group1-sha1 -l $username $hostname
expect "password:" { send "$password\r" }
# device manager
expect "> " { send "1\r" }
# outlet control
expect "> " { send "2\r" }
# outlet number
expect "> " { send "$outlet\r" }
# state
expect "> " { send "$state\r" }
# control outlet
expect "to cancel : " { send "YES\r" }
# continue, return and logout
expect "to continue..." { send "\r" }
expect "> " { send \033 }
expect "> " { send \033 }
expect "> " { send \033 }
expect "> " { send "4\r" }