#!/bin/bash # Nightly Traefik dynamic_conf.yml drift check # Runs on ansible-control; alerts to ntfy if node01 and node02 differ # beyond the known intentional crowdsecLapiHost difference. NODE01="tommy@192.168.99.186" NODE02="tommy@192.168.99.187" CONF_PATH="/home/tommy/traefik/dynamic_conf.yml" NTFY_URL="https://ntfy.goattw.net/homelab-alerts" KNOWN_DIFF_PATTERN="crowdsecLapiHost" logger -t traefik-drift-check "starting drift check" node01_content=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$NODE01" "cat $CONF_PATH" 2>/dev/null) node02_content=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$NODE02" "cat $CONF_PATH" 2>/dev/null) if [[ -z "$node01_content" || -z "$node02_content" ]]; then logger -t traefik-drift-check "ERROR: could not fetch config from one or both nodes" curl -sf \ -H "Priority: high" \ -H "Tags: warning" \ -H "Title: Traefik drift-check: fetch failed" \ -d "Could not SSH to node01 or node02 to fetch dynamic_conf.yml" \ "$NTFY_URL" || true exit 1 fi # Diff, filter out the known intentional line unexpected_diff=$(diff \ <(echo "$node01_content" | grep -v "$KNOWN_DIFF_PATTERN") \ <(echo "$node02_content" | grep -v "$KNOWN_DIFF_PATTERN") 2>/dev/null) if [[ -n "$unexpected_diff" ]]; then logger -t traefik-drift-check "DRIFT DETECTED — unexpected differences found" diff_summary=$(echo "$unexpected_diff" | head -20) curl -sf \ -H "Priority: high" \ -H "Tags: warning" \ -H "Title: Traefik config drift detected" \ -d "dynamic_conf.yml differs between node01 and node02 (beyond crowdsecLapiHost). $diff_summary Fix: sync node02 from node01 canonical." \ "$NTFY_URL" || true logger -t traefik-drift-check "alert sent to ntfy" exit 1 else logger -t traefik-drift-check "no unexpected drift — configs match (crowdsecLapiHost difference expected)" exit 0 fi