#!/bin/bash # UPS heartbeat check - managed by Ansible (infra/nodito/34_nut_ups_setup_playbook.yml) # # The exit code is the answer and systemd keeps it: # systemctl is-failed {{ ups_systemd_service_name }}.service # Reporting anywhere else is optional and generic. LOG_FILE="{{ ups_log_file }}" UPS_NAME="{{ ups_name }}" PUSH_URL="${HEALTHCHECK_PUSH_URL:-}" log_message() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE" } report() { local status="$1" local message="$2" # No push URL is normal, not an error: the exit code below is still a # complete answer for anything reading unit state. [ -n "$PUSH_URL" ] || return 0 local encoded_message encoded_message=$(printf '%s\n' "$message" | sed 's/%/%25/g; s/ /%20/g; s/(/%28/g; s/)/%29/g; s/:/%3A/g; s/\//%2F/g') local response http_code response=$(curl -s --max-time 10 --retry 2 -w "\n%{http_code}" "${PUSH_URL}?status=${status}&msg=${encoded_message}&ping=" 2>&1) http_code=$(echo "$response" | tail -n1) if [ "$http_code" = "200" ] || [ "$http_code" = "201" ]; then log_message "Reported ${status}: $message (HTTP $http_code)" return 0 else log_message "ERROR: Failed to report ${status} (HTTP $http_code)" return 1 fi } main() { local status charge runtime load status=$(upsc ${UPS_NAME}@localhost ups.status 2>/dev/null) if [ -z "$status" ]; then log_message "ERROR: Cannot communicate with UPS" report "down" "cannot communicate with UPS ${UPS_NAME}" exit 1 fi charge=$(upsc ${UPS_NAME}@localhost battery.charge 2>/dev/null) runtime=$(upsc ${UPS_NAME}@localhost battery.runtime 2>/dev/null) load=$(upsc ${UPS_NAME}@localhost ups.load 2>/dev/null) if [[ "$status" == *"OL"* ]]; then local message="UPS on mains (charge=${charge}% runtime=${runtime}s load=${load}%)" log_message "$message" report "up" "$message" exit 0 else log_message "UPS not on mains power (status=$status)" report "down" "UPS not on mains (status=${status} charge=${charge}%)" exit 1 fi } main