#!/usr/bin/env bash
#
# Stop this VM after it has been idle for a while, so an unused machine does
# not bill all night. Installs two small files and a timer, then gets out of
# the way.
#
#   IDLE   nobody logged in, and the 1-minute load average is low
#   BUSY   anyone logged in over SSH, or real CPU work happening
#
# Optional helper, not a spending cap or a reliable work detector.
# who and CPU load can miss downloads, background services, and some sessions.
# It may stop the VM during low-CPU work. Save backups; do not use on shared VMs.
# Disable the timer before unattended work. Disks and networking can still bill.
#
# Read this file before you run it. That is the rule for every installer in
# this course, including this one.
#
# Install:   sudo bash idle-shutdown.sh
# Undo:      sudo systemctl disable --now idle-shutdown.timer
# Watch it:  tail -f /var/log/idle-shutdown.log
#
set -euo pipefail

IDLE_MINUTES="${IDLE_MINUTES:-60}"
CHECK_MINUTES="${CHECK_MINUTES:-5}"
LOAD_BUSY="${LOAD_BUSY:-0.4}"

if [ "$(id -u)" -ne 0 ]; then
  echo "Run this with sudo: sudo bash idle-shutdown.sh" >&2
  exit 1
fi

echo "Installing the idle check: stop after ${IDLE_MINUTES} minutes classified as idle by login and CPU checks."

install -d -m 0755 /var/lib/idle-shutdown

cat > /usr/local/sbin/idle-shutdown.sh <<EOF
#!/usr/bin/env bash
# Written by idle-shutdown.sh from edcadet.com/bootcamp. Safe to delete.
set -euo pipefail

IDLE_MINUTES=${IDLE_MINUTES}
CHECK_MINUTES=${CHECK_MINUTES}
LOAD_BUSY=${LOAD_BUSY}
STATE=/var/lib/idle-shutdown/idle_minutes
LOG=/var/log/idle-shutdown.log

[ -f "\$STATE" ] || echo 0 > "\$STATE"

busy=0
reason=idle

# Sessions listed by who count as busy. Not every shell appears there.
if who | grep -q . ; then
  busy=1
  reason=logged-in
fi

# Higher CPU load counts as busy; low-CPU work can still be missed.
load=\$(awk '{print \$1}' /proc/loadavg)
if awk -v l="\$load" -v b="\$LOAD_BUSY" 'BEGIN{exit !(l > b)}'; then
  busy=1
  reason=cpu-busy
fi

count=\$(cat "\$STATE")
if [ "\$busy" -eq 1 ]; then
  count=0
else
  count=\$(( count + CHECK_MINUTES ))
fi
echo "\$count" > "\$STATE"

printf '%s %s load=%s idle_for=%sm of %sm\n' \\
  "\$(date -Is)" "\$reason" "\$load" "\$count" "\$IDLE_MINUTES" >> "\$LOG"

if [ "\$count" -ge "\$IDLE_MINUTES" ]; then
  printf '%s stopping the VM after %s idle minutes\n' "\$(date -Is)" "\$count" >> "\$LOG"
  echo 0 > "\$STATE"
  /sbin/shutdown -h now "Idle for \$IDLE_MINUTES minutes"
fi
EOF
chmod 0755 /usr/local/sbin/idle-shutdown.sh

cat > /etc/systemd/system/idle-shutdown.service <<'EOF'
[Unit]
Description=Stop this VM when it has been idle

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/idle-shutdown.sh
EOF

cat > /etc/systemd/system/idle-shutdown.timer <<EOF
[Unit]
Description=Check every ${CHECK_MINUTES} minutes whether this VM is idle

[Timer]
OnBootSec=10min
OnUnitActiveSec=${CHECK_MINUTES}min
AccuracySec=30s

[Install]
WantedBy=timers.target
EOF

touch /var/log/idle-shutdown.log
chmod 0644 /var/log/idle-shutdown.log

systemctl daemon-reload
systemctl enable --now idle-shutdown.timer

echo
echo "Done. The VM now stops after ${IDLE_MINUTES} idle minutes."
echo "Next check:"
systemctl list-timers idle-shutdown.timer --no-pager | sed -n '1,2p'
echo
echo "Watch it decide:  tail -f /var/log/idle-shutdown.log"
echo "Turn it off:      sudo systemctl disable --now idle-shutdown.timer"
echo
echo "Starting the VM again is a button in your provider console."
