Skip to content

Instantly share code, notes, and snippets.

@alanwoolley
Last active May 21, 2023 19:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alanwoolley/c5ddb8e6692fd5f492605d271edad0a2 to your computer and use it in GitHub Desktop.
Save alanwoolley/c5ddb8e6692fd5f492605d271edad0a2 to your computer and use it in GitHub Desktop.
Puts QNAP NAS to sleep if idle
#!/bin/bash
SUSPENDTHRESHOLD=1800
LOADTHRESHOLD=1.7
PACKETSTHRESHOLD=40
NFS_PORT=2049
SMB_PORT=445
NETWORKINTERFACE=bond0
DRY_RUN=false
# Color escape sequences
RED='\033[0;31m'
NC='\033[0m' # No Color
check_load_threshold() {
local load_name=$1
local load_value=$2
local threshold=$3
# Use awk for decimal comparisons since load average values are in decimal format
if awk -v load="$load_value" -v threshold="$threshold" 'BEGIN { exit !(load < threshold) }'; then
return 0 # Load condition is below threshold, indicating success
else
echo "Load condition failed for ${load_name}: ${load_value} >= ${threshold}"
return 1 # Load condition exceeds threshold, indicating failure
fi
}
check_load_thresholds() {
echo "Checking load thresholds..."
local LOAD=$(cat /proc/loadavg)
local load_avg_1min=$(echo "$LOAD" | awk '{printf "%.2f", $1}')
local load_avg_5min=$(echo "$LOAD" | awk '{printf "%.2f", $2}')
local load_avg_15min=$(echo "$LOAD" | awk '{printf "%.2f", $3}')
echo "Load Average (1min/5min/15min): $load_avg_1min $load_avg_5min $load_avg_15min"
failed_conditions=()
if ! check_load_threshold "1-minute Load Average" "$load_avg_1min" "$LOADTHRESHOLD"; then
failed_conditions+=("1-minute Load Average")
fi
if ! check_load_threshold "5-minute Load Average" "$load_avg_5min" "$LOADTHRESHOLD"; then
failed_conditions+=("5-minute Load Average")
fi
if ! check_load_threshold "15-minute Load Average" "$load_avg_15min" "$LOADTHRESHOLD"; then
failed_conditions+=("15-minute Load Average")
fi
if [ ${#failed_conditions[@]} -eq 0 ]; then
return 0 # Success: All load conditions are below threshold
else
echo "Load condition(s) failed."
return 1 # Failure: One or more load conditions exceed threshold
fi
}
check_clients_connected() {
local port=$1
echo -n "Checking clients connected on port ${port}... "
local connected_clients=$(netstat -an | grep ":${port}" | grep "ESTABLISHED" | wc -l)
echo "$connected_clients"
if [ "$connected_clients" -ge 1 ]; then
echo "Multiple clients connected to port ${port}: $connected_clients"
return 1 # failure
else
return 0 # success
fi
}
check_packets_threshold() {
echo -n "Checking for average network utilisation... "
local PACKETS=$(/opt/bin/vnstat -tr 180 -s -i "$NETWORKINTERFACE" | awk '$1 ~ /(r|t)x/ {sum+= $4} END {print sum}')
echo "${PACKETS} packets"
if [ "$PACKETS" -lt "$PACKETSTHRESHOLD" ]; then
echo "Packet condition passed."
return 0 # success
else
echo "Packet condition failed."
return 1 # failure
fi
}
suspend() {
echo "Suspending"
echo "mem" > /sys/power/state
}
check_time_since_suspend() {
echo "Checking time since last suspension..."
local suspend_threshold=$1
NOW=$(date +%s)
LASTSUSPENDDATE=$(cat /mnt/HDA_ROOT/.logs/kmsg | grep "PM: suspend exit" | tail -n1 | awk '{print $1, $2, $3}')
LASTSUSPENDUNIX=$(date -d "$LASTSUSPENDDATE" +%s)
TIMESINCESUSPEND=$(dc $NOW $LASTSUSPENDUNIX - p)
if [ -z "$TIMESINCESUSPEND" ]; then
TIMESINCESUSPEND=0
fi
echo "Suspended $TIMESINCESUSPEND seconds ago"
if [ "$TIMESINCESUSPEND" -gt "$suspend_threshold" ]; then
return 0 # success
else
echo "Time since last suspend is less than the threshold."
return 1 # failure
fi
}
# Process command-line options
while getopts ":d" opt; do
case $opt in
d) # Option '-d' is specified, indicating dry-run mode
DRY_RUN=true
;;
\?) # Invalid option encountered
echo -e "${RED}Invalid option: -$OPTARG${NC}" >&2
exit 1
;;
esac
done
shift $((OPTIND - 1)) # Shifts the positional parameters to exclude processed options
# Perform all the checks, but skip suspension if any check fails
all_checks_pass=true
check_time_since_suspend "$SUSPENDTHRESHOLD" || { echo -e "${RED}Time since last suspend is less than the threshold.${NC}"; all_checks_pass=false; }
check_load_thresholds || { echo -e "${RED}Load condition(s) failed.${NC}"; all_checks_pass=false; }
check_clients_connected "$SMB_PORT" || { echo -e "${RED}Multiple clients connected to port ${SMB_PORT}.${NC}"; all_checks_pass=false; }
check_clients_connected "$NFS_PORT" || { echo -e "${RED}Multiple clients connected to port ${NFS_PORT}.${NC}"; all_checks_pass=false; }
check_packets_threshold || { echo -e "${RED}Packet condition failed.${NC}"; all_checks_pass=false; }
# Check if all checks passed
if [ "$all_checks_pass" = true ]; then
if [ "$DRY_RUN" = true ]; then
echo "Performing dry-run (no actual suspension)"
else
suspend
fi
else
echo "${RED}One or more conditions failed. Skipping suspension.${NC}"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment