267 lines
12 KiB
Bash
267 lines
12 KiB
Bash
#!/bin/bash
|
|
# ==============================================================================================
|
|
# ================================= WebGUI Watchdog ============================================
|
|
# ==============================================================================================
|
|
# Monitors the unRAID WebGUI and restarts services if unresponsive.
|
|
# Uses a three-step escalating strategy — lightest fix first, heaviest last.
|
|
# Run every 5-10 minutes via User Scripts plugin.
|
|
# Silent when healthy — only produces output when something needs fixing.
|
|
#
|
|
# ── ESCALATION PATH ───────────────────────────────────────────────────────────────────────────
|
|
# Check WebGUI → responding → log() + exit 0 (completely silent ✅)
|
|
#
|
|
# Not responding:
|
|
# Step 1 — Restart nginx
|
|
# Lightest fix — handles most transient WebGUI failures
|
|
# nginx crash, worker stuck, connection timeout
|
|
# Wait WEBGUI_NGINX_WAIT seconds → recheck
|
|
#
|
|
# Step 2 — Restart php-fpm
|
|
# WebGUI runs through PHP-FPM — worker exhaustion causes silent failure
|
|
# php-fpm workers saturated → new requests queue → WebGUI appears frozen
|
|
# system_tuning_monitor.sh tracks usage — this recovers it
|
|
# Wait WEBGUI_PHP_WAIT seconds → recheck
|
|
#
|
|
# Step 3 — Restart emhttp
|
|
# Heaviest fix — emhttp is the unRAID management daemon
|
|
# Array, Docker, shares stay running — only WebGUI management restarts
|
|
# Takes longer to recover — WEBGUI_EMHTTP_WAIT gives it time
|
|
# Wait WEBGUI_EMHTTP_WAIT seconds → recheck
|
|
#
|
|
# All three failed → notify warning, manual intervention needed → exit 1
|
|
#
|
|
# ── HOST AWARENESS ────────────────────────────────────────────────────────────────────────────
|
|
# detect_hosts() sets MY_ID — used in all notifications and summary.
|
|
# Critical on two-server setup — which server's WebGUI failed?
|
|
#
|
|
# ── SAFEGUARDS ────────────────────────────────────────────────────────────────────────────────
|
|
# acquire_lock — prevents concurrent runs double-restarting services
|
|
# detect_hosts() — MY_ID in all notifications
|
|
# Process verify — pgrep check after each service restart
|
|
# Silent healthy — completely silent on healthy cycle ✅
|
|
# validate_unraid_cmd — notify validated before use
|
|
#
|
|
# ── CONFIGURATION (master.conf) ───────────────────────────────────────────────────────────────
|
|
# WEBGUI_URL — URL to check (default http://localhost)
|
|
# WEBGUI_TIMEOUT — curl timeout in seconds (default 5)
|
|
# WEBGUI_NGINX_WAIT — seconds after nginx restart before rechecking (default 15)
|
|
# WEBGUI_PHP_WAIT — seconds after php-fpm restart before rechecking (default 10)
|
|
# WEBGUI_EMHTTP_WAIT — seconds after emhttp restart before rechecking (default 30)
|
|
#
|
|
# ── USAGE ─────────────────────────────────────────────────────────────────────────────────────
|
|
# webgui_restart.sh — check and recover if needed
|
|
# webgui_restart.sh --dry-run — show what would be restarted
|
|
# webgui_restart.sh --status — show current WebGUI and service states
|
|
# webgui_restart.sh --log — verbose output
|
|
# ==============================================================================================
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
source "$SCRIPT_DIR/../load_config.sh"
|
|
|
|
parse_args "$@"
|
|
|
|
# ==============================================================================================
|
|
# ━━━ Setup ━━━
|
|
# ==============================================================================================
|
|
if [[ "$EUID" -ne 0 ]]; then
|
|
error "Must be run as root"
|
|
exit 1
|
|
fi
|
|
|
|
validate_unraid_cmd \
|
|
"/usr/local/emhttp/plugins/dynamix/scripts/notify" \
|
|
"" "" \
|
|
"unRAID notify script" || warn "unRAID notify script not found — native notifications disabled"
|
|
|
|
acquire_lock
|
|
|
|
detect_hosts
|
|
|
|
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no services will be restarted"
|
|
|
|
# ==============================================================================================
|
|
# ━━━ Status ━━━
|
|
# ==============================================================================================
|
|
if [[ "$SHOW_STATUS" == true ]]; then
|
|
echo ""
|
|
echo "━━━━━ $ICON_SUMMARY WEBGUI WATCHDOG STATUS ━━━━━"
|
|
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
|
|
echo "$ICON_WEBGUI URL: $WEBGUI_URL"
|
|
echo "$ICON_WEBGUI Timeouts: curl=${WEBGUI_TIMEOUT}s nginx=${WEBGUI_NGINX_WAIT}s php=${WEBGUI_PHP_WAIT:-10}s emhttp=${WEBGUI_EMHTTP_WAIT}s"
|
|
echo ""
|
|
|
|
if curl -sf --max-time "$WEBGUI_TIMEOUT" "$WEBGUI_URL" >/dev/null 2>&1; then
|
|
echo " $ICON_SUCCESS WebGUI: responding ✅"
|
|
else
|
|
echo " $ICON_ERROR WebGUI: NOT responding"
|
|
fi
|
|
|
|
pgrep -x nginx >/dev/null 2>&1 && \
|
|
echo " $ICON_SUCCESS nginx: running ✅" || \
|
|
echo " $ICON_ERROR nginx: NOT running"
|
|
|
|
pgrep -f "php-fpm" >/dev/null 2>&1 && \
|
|
FPM_COUNT=$(pgrep -fc "php-fpm" 2>/dev/null || echo "?") && \
|
|
echo " $ICON_SUCCESS php-fpm: running ($FPM_COUNT workers) ✅" || \
|
|
echo " $ICON_ERROR php-fpm: NOT running"
|
|
|
|
pgrep -x emhttp >/dev/null 2>&1 && \
|
|
echo " $ICON_SUCCESS emhttp: running ✅" || \
|
|
echo " $ICON_ERROR emhttp: NOT running"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━"
|
|
exit 0
|
|
fi
|
|
|
|
# ==============================================================================================
|
|
# ── CHECK AND ESCALATE ────────────────────────────────────────────────────────────────────────
|
|
# ==============================================================================================
|
|
check_webgui() {
|
|
curl -sf --max-time "$WEBGUI_TIMEOUT" "$WEBGUI_URL" >/dev/null 2>&1
|
|
}
|
|
|
|
START=$(date +%s)
|
|
RECOVERY_ACTION=""
|
|
RECOVERY_OK=false
|
|
|
|
log "WebGUI check — $WEBGUI_URL"
|
|
|
|
# ── Healthy — completely silent ───────────────────────────────────────────────────────────────
|
|
if check_webgui; then
|
|
log "WebGUI responding — healthy ✅"
|
|
exit 0
|
|
fi
|
|
|
|
# ── Not responding — begin escalation ────────────────────────────────────────────────────────
|
|
echo ""
|
|
echo "━━━ $ICON_WEBGUI WebGUI Watchdog — $(date '+%Y-%m-%d %H:%M:%S') ━━━"
|
|
echo "$ICON_HOST $MY_ID ($LOCAL_SERVER_NAME)"
|
|
echo ""
|
|
warn "WebGUI not responding at $WEBGUI_URL — beginning escalation"
|
|
|
|
# ── Step 1 — nginx restart ────────────────────────────────────────────────────────────────────
|
|
echo ""
|
|
echo "━━━ Step 1 — nginx Restart ━━━"
|
|
|
|
if [[ "$DRY_RUN" == true ]]; then
|
|
warn "DRY RUN — would restart nginx"
|
|
else
|
|
warn "Restarting nginx..."
|
|
if /etc/rc.d/rc.nginx restart >/dev/null 2>&1; then
|
|
# Verify nginx actually running
|
|
sleep 2
|
|
if pgrep -x nginx >/dev/null 2>&1; then
|
|
warn "nginx restarted ✅"
|
|
else
|
|
error "nginx not running after restart command"
|
|
fi
|
|
else
|
|
error "nginx restart command failed"
|
|
fi
|
|
|
|
log "Waiting ${WEBGUI_NGINX_WAIT}s for nginx to recover..."
|
|
sleep "$WEBGUI_NGINX_WAIT"
|
|
|
|
if check_webgui; then
|
|
RECOVERY_ACTION="nginx restart"
|
|
RECOVERY_OK=true
|
|
fi
|
|
fi
|
|
|
|
# ── Step 2 — php-fpm restart ──────────────────────────────────────────────────────────────────
|
|
if [[ "$RECOVERY_OK" == false ]]; then
|
|
echo ""
|
|
echo "━━━ Step 2 — php-fpm Restart ━━━"
|
|
warn "WebGUI still not responding — restarting php-fpm"
|
|
warn "WebGUI may be frozen due to worker exhaustion (check system_tuning_monitor.sh)"
|
|
|
|
if [[ "$DRY_RUN" == true ]]; then
|
|
warn "DRY RUN — would restart php-fpm"
|
|
else
|
|
if /etc/rc.d/rc.php-fpm restart >/dev/null 2>&1; then
|
|
sleep 2
|
|
if pgrep -f "php-fpm" >/dev/null 2>&1; then
|
|
warn "php-fpm restarted ✅"
|
|
else
|
|
error "php-fpm not running after restart command"
|
|
fi
|
|
else
|
|
error "php-fpm restart command failed"
|
|
fi
|
|
|
|
log "Waiting ${WEBGUI_PHP_WAIT:-10}s for php-fpm to recover..."
|
|
sleep "${WEBGUI_PHP_WAIT:-10}"
|
|
|
|
if check_webgui; then
|
|
RECOVERY_ACTION="php-fpm restart"
|
|
RECOVERY_OK=true
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# ── Step 3 — emhttp restart ───────────────────────────────────────────────────────────────────
|
|
if [[ "$RECOVERY_OK" == false ]]; then
|
|
echo ""
|
|
echo "━━━ Step 3 — emhttp Restart ━━━"
|
|
warn "WebGUI still not responding — restarting emhttp (unRAID management daemon)"
|
|
warn "Array, Docker, and shares remain running — WebGUI management will briefly restart"
|
|
|
|
if [[ "$DRY_RUN" == true ]]; then
|
|
warn "DRY RUN — would restart emhttp"
|
|
else
|
|
if /etc/rc.d/rc.emhttp restart >/dev/null 2>&1; then
|
|
sleep 2
|
|
if pgrep -x emhttp >/dev/null 2>&1; then
|
|
warn "emhttp restarted ✅"
|
|
else
|
|
error "emhttp not running after restart command"
|
|
fi
|
|
else
|
|
error "emhttp restart command failed"
|
|
fi
|
|
|
|
log "Waiting ${WEBGUI_EMHTTP_WAIT}s for emhttp to recover..."
|
|
sleep "$WEBGUI_EMHTTP_WAIT"
|
|
|
|
if check_webgui; then
|
|
RECOVERY_ACTION="emhttp restart"
|
|
RECOVERY_OK=true
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
END=$(date +%s)
|
|
|
|
# ==============================================================================================
|
|
# ━━━ Summary ━━━
|
|
# ==============================================================================================
|
|
echo ""
|
|
echo "━━━━━ $ICON_SUMMARY WEBGUI WATCHDOG SUMMARY ━━━━━"
|
|
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
|
|
echo "$ICON_WEBGUI URL: $WEBGUI_URL"
|
|
echo "$ICON_TIME Duration: $(format_duration $(( END - START )))"
|
|
echo ""
|
|
|
|
if [[ "$DRY_RUN" == true ]]; then
|
|
warn "DRY RUN — no services restarted"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "$RECOVERY_OK" == true ]]; then
|
|
warn "$ICON_SUCCESS WebGUI recovered via: $RECOVERY_ACTION"
|
|
notify "WebGUI recovered on $(hostname) ($MY_ID) via $RECOVERY_ACTION — monitor for recurrence" \
|
|
"WebGUI Watchdog" "warning"
|
|
else
|
|
echo "$ICON_ERROR Status: UNRECOVERED — all three restart steps failed"
|
|
echo "$ICON_ERROR Manual intervention needed:"
|
|
echo " 1. Check: pgrep -x nginx emhttp"
|
|
echo " 2. Check: journalctl -u nginx --since '10 minutes ago'"
|
|
echo " 3. Try: server_reboot.sh if nothing else works"
|
|
notify "WebGUI UNRECOVERED on $(hostname) ($MY_ID) — nginx + php-fpm + emhttp restart all failed — manual intervention needed" \
|
|
"WebGUI Watchdog" "warning"
|
|
fi
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
[[ "$RECOVERY_OK" == false && "$DRY_RUN" == false ]] && exit 1
|
|
exit 0 |