#!/usr/bin/env bash set -euo pipefail HOMELAB_STATE_DIR="${HOMELAB_STATE_DIR:-${XDG_DATA_HOME:-${HOME}/.local/share}/homelab}" GITEA_BACKUP_DIR="${LAB_GITEA_BACKUP_DIR:-/home/jv/backups/gitea}" GITEA_DRILL_DIR="${GITEA_RESTORE_DRILL_DIR:-/home/jv/backups/gitea-restore-drills}" TOFU_BACKUP_DIR="${HOMELAB_TOFU_STATE_BACKUP_DIR:-${HOMELAB_STATE_DIR}/tofu-state-backups}" PIHOLE_CONFIG_FILES="${PIHOLE_CONFIG_FILES:-infra/rpi-services/adlists.txt infra/rpi-services/local-dns-records.txt infra/rpi-services/cname-records.txt infra/rpi-services/static-dhcp-hosts.txt}" MAX_GITEA_AGE_HOURS="${LAB_BACKUP_MAX_GITEA_AGE_HOURS:-36}" MAX_TOFU_AGE_HOURS="${LAB_BACKUP_MAX_TOFU_AGE_HOURS:-168}" MAX_DRILL_AGE_HOURS="${LAB_BACKUP_MAX_DRILL_AGE_HOURS:-744}" failures=0 warnings=0 section() { printf '\n== %s ==\n' "$1" } latest_file() { local dir="$1" local pattern="$2" if [ -d "$dir" ]; then find "$dir" -maxdepth 1 -type f -name "$pattern" -printf '%T@ %p\n' 2>/dev/null | sort -n | tail -1 | sed 's/^[^ ]* //' fi } file_age_hours() { local path="$1" python3 - "$path" <<'PY' import os import sys import time path = sys.argv[1] age = int((time.time() - os.path.getmtime(path)) / 3600) print(age) PY } check_latest() { local label="$1" local dir="$2" local pattern="$3" local max_age_hours="$4" local severity="${5:-fail}" local latest local age_hours latest="$(latest_file "$dir" "$pattern" || true)" printf '%-30s ' "$label" if [ -z "$latest" ]; then printf '%s - missing in %s\n' "$severity" "$dir" if [ "$severity" = "fail" ]; then failures=$((failures + 1)) else warnings=$((warnings + 1)) fi return 0 fi age_hours="$(file_age_hours "$latest")" if [ "$age_hours" -le "$max_age_hours" ]; then printf 'ok - age=%sh path=%s\n' "$age_hours" "$latest" else printf '%s - age=%sh max=%sh path=%s\n' "$severity" "$age_hours" "$max_age_hours" "$latest" if [ "$severity" = "fail" ]; then failures=$((failures + 1)) else warnings=$((warnings + 1)) fi fi } section "Backup Freshness" check_latest "Gitea backup" "$GITEA_BACKUP_DIR" 'gitea-*.zip' "$MAX_GITEA_AGE_HOURS" fail check_latest "OpenTofu state backup" "$TOFU_BACKUP_DIR" 'tofu-state-*.tgz' "$MAX_TOFU_AGE_HOURS" warn check_latest "Restore drill report" "$GITEA_DRILL_DIR" 'restore-drill-*.txt' "$MAX_DRILL_AGE_HOURS" warn section "Repo Managed Pi-hole Inputs" for file in $PIHOLE_CONFIG_FILES; do printf '%-30s ' "$file" if [ -s "$file" ]; then printf 'ok\n' else printf 'warn - missing or empty\n' warnings=$((warnings + 1)) fi done section "Summary" printf 'failures=%s warnings=%s\n' "$failures" "$warnings" if [ "$failures" -gt 0 ]; then exit 1 fi