Files
dns-updater/packaging/facts.d/dns_updater.sh
T
unkinben 02e3e0315d
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Initial implementation: dns-updater daemon
RFC2136 dynamic-DNS updater. Watches a records file (inotify) and new
interface addresses and pushes TSIG-signed updates to BIND per zone, sending
only the delta. Native miekg/dns (structured per-zone RCODEs), local status
API + facter fact, systemd unit, nfpm RPM, Woodpecker CI.

Replaces the puppet dns-update shell script; keeps the same records-file and
TSIG-key contract.
2026-07-17 23:24:49 +10:00

56 lines
1.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Facter external fact: report dns-updater's status by querying its local API
# socket. Emits flat key=value facts (compatible across facter versions).
# Puppet already knows the DESIRED records (it writes the records file); these
# facts report what the daemon actually achieved on the server.
set -u
SOCK="${DNS_UPDATER_API_SOCK:-/run/dns-updater/api.sock}"
emit() { printf 'dns_updater_%s=%s\n' "$1" "$2"; }
if [ ! -S "$SOCK" ]; then
emit running false
emit healthy false
exit 0
fi
json="$(curl -s --max-time 3 --unix-socket "$SOCK" http://local/status 2>/dev/null)"
if [ -z "$json" ]; then
emit running true
emit healthy false
emit last_error "api_unreachable"
exit 0
fi
emit running true
python3 - "$json" <<'PY'
import json, sys
try:
d = json.loads(sys.argv[1])
except Exception:
print("dns_updater_healthy=false")
print("dns_updater_last_error=bad_json")
sys.exit(0)
def emit(k, v):
print(f"dns_updater_{k}={v}")
emit("healthy", str(d.get("healthy", False)).lower())
emit("managed_records", d.get("managed_records", 0))
if d.get("last_reconcile"):
emit("last_reconcile", d["last_reconcile"])
if d.get("last_change"):
emit("last_change", d["last_change"])
if d.get("last_error"):
emit("last_error", d["last_error"].replace("\n", " ")[:200])
zones = d.get("zones") or []
failed = [z for z in zones if (z.get("error") or z.get("rcode", 0) != 0)]
emit("zones_total", len(zones))
emit("zones_failed", len(failed))
if failed:
emit("failed_zones", ",".join(f"{z['zone']}:{z.get('rcode_text','?')}" for z in failed))
PY