Commit the accumulated infrastructure work that was living only in the working tree: monitoring stack, emergency access/bot, gyro allocator, grimmory, adguard, backup audit and the OpenCode agent definitions. Also ignore Python bytecode, local archives and Nix/direnv artifacts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTocXkGUUazHdKKd3r9k71
71 lines
2.4 KiB
Django/Jinja
71 lines
2.4 KiB
Django/Jinja
#!/bin/sh
|
|
# Managed by Ansible: HomeLab PBS backup audit (L0 freshness)
|
|
set -eu
|
|
|
|
LOG_FILE="{{ backup_audit_log_file }}"
|
|
METRICS_DIR="{{ backup_audit_metrics_dir }}"
|
|
METRICS_FILE="$METRICS_DIR/homelab_backup_audit_pbs.prom"
|
|
METRICS_TMP=$(mktemp "$METRICS_FILE.XXXXXX")
|
|
STATUS=OK
|
|
NOW_EPOCH=$(date +%s)
|
|
|
|
trap 'rm -f "$METRICS_TMP"' EXIT
|
|
|
|
publish_metrics() {
|
|
chmod 0644 "$METRICS_TMP"
|
|
mv "$METRICS_TMP" "$METRICS_FILE"
|
|
}
|
|
|
|
ts() { date '+%Y-%m-%dT%H:%M:%S%z'; }
|
|
log() { echo "[$(ts)] [pbs] $*" | tee -a "$LOG_FILE"; }
|
|
|
|
get_latest_snapshot() {
|
|
pvesm list pbs --vmid "$1" 2>/dev/null \
|
|
| tail -n +2 \
|
|
| awk '{print $1}' \
|
|
| sort -t/ -k4 \
|
|
| tail -1
|
|
}
|
|
|
|
{% for entry in backup_audit_pbs_vmids %}
|
|
audit_vmid_{{ entry.vmid }}() {
|
|
vmid={{ entry.vmid }}
|
|
max_age={{ entry.max_age_hours }}
|
|
latest=$(get_latest_snapshot "$vmid")
|
|
if [ -z "$latest" ]; then
|
|
log "FAIL L0: vmid $vmid — no snapshots in PBS"
|
|
printf 'homelab_backup_audit_snapshot_age_hours{profile="pbs",vmid="%s"} -1\n' "$vmid" >> "$METRICS_TMP"
|
|
printf 'homelab_backup_audit_snapshot_success{profile="pbs",vmid="%s"} 0\n' "$vmid" >> "$METRICS_TMP"
|
|
STATUS=FAIL
|
|
return
|
|
fi
|
|
ts_str=$(printf '%s' "$latest" | sed -n 's#.*/\([0-9T:Z-]*\)$#\1#p')
|
|
snap_epoch=$(date -d "$ts_str" +%s 2>/dev/null || echo 0)
|
|
age_hours=$(( (NOW_EPOCH - snap_epoch) / 3600 ))
|
|
if [ "$age_hours" -gt "$max_age" ]; then
|
|
log "FAIL L0: vmid $vmid — latest snapshot age ${age_hours}h > ${max_age}h (snapshot: $ts_str)"
|
|
printf 'homelab_backup_audit_snapshot_success{profile="pbs",vmid="%s"} 0\n' "$vmid" >> "$METRICS_TMP"
|
|
STATUS=FAIL
|
|
else
|
|
log "OK L0: vmid $vmid — latest snapshot age ${age_hours}h"
|
|
printf 'homelab_backup_audit_snapshot_success{profile="pbs",vmid="%s"} 1\n' "$vmid" >> "$METRICS_TMP"
|
|
fi
|
|
printf 'homelab_backup_audit_snapshot_age_hours{profile="pbs",vmid="%s"} %s\n' "$vmid" "$age_hours" >> "$METRICS_TMP"
|
|
}
|
|
audit_vmid_{{ entry.vmid }}
|
|
|
|
{% endfor %}
|
|
if [ "$STATUS" = "OK" ]; then
|
|
log "AUDIT PASSED"
|
|
printf 'homelab_backup_audit_success{profile="pbs"} 1\n' >> "$METRICS_TMP"
|
|
printf 'homelab_backup_audit_timestamp_seconds{profile="pbs"} %s\n' "$NOW_EPOCH" >> "$METRICS_TMP"
|
|
publish_metrics
|
|
exit 0
|
|
else
|
|
log "AUDIT FAILED"
|
|
printf 'homelab_backup_audit_success{profile="pbs"} 0\n' >> "$METRICS_TMP"
|
|
printf 'homelab_backup_audit_timestamp_seconds{profile="pbs"} %s\n' "$NOW_EPOCH" >> "$METRICS_TMP"
|
|
publish_metrics
|
|
exit 1
|
|
fi
|