chore: initial import from KNEL/PFVCluster@041d311 [#769]
Split per O&M lane work order. Full history: KNEL/PFVCluster. https://projects.knownelement.com/issues/769#note-4152
This commit is contained in:
Executable
+115
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/bash
|
||||
#
|
||||
# drift-check.sh — compare live netinfra DNS/DHCP config against git [#420][#469]
|
||||
#
|
||||
# Verifies that the running configuration on netinfra-01/02 matches the
|
||||
# files tracked in this repo. Founded after the 2026-09-01 DNS incident:
|
||||
# the live systems are production; git is the source of truth; drift is
|
||||
# a defect.
|
||||
#
|
||||
# Checks per node:
|
||||
# - /etc/dhcp/dhcpd.conf vs netinfra/dhcp/dhcpd-{primary,secondary}.conf
|
||||
# - /etc/pihole/pihole.toml vs netinfra/dns/pihole/netinfra-0{1,2}.pihole.toml
|
||||
# (secrets redacted on both sides before compare; "Last updated" line ignored)
|
||||
# - /etc/ntpsec/ntp.conf vs netinfra/ntp/ntp.conf (nodes are identical)
|
||||
# - Technitium zones (node 01, the replication primary): md5 manifest of the
|
||||
# binary DZ store vs netinfra/dns/technitium/zones/ [#630]
|
||||
#
|
||||
# Usage:
|
||||
# drift-check.sh [--node 01|02|all] (default: all)
|
||||
# Exit: 0 = in sync, 1 = drift detected, 2 = fetch failure
|
||||
#
|
||||
set -uo pipefail
|
||||
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
DNS_SETUP="$HERE/dns-cluster-setup"
|
||||
DHCP_DIR="$HERE/dhcp"
|
||||
PIHOLE_DIR="$HERE/dns/pihole"
|
||||
NTP_FILE="$HERE/ntp/ntp.conf"
|
||||
ZONES_DIR="$HERE/dns/technitium/zones"
|
||||
REMOTE_ZONE_DIR="/home/localuser/services/technitium/config/zones"
|
||||
|
||||
REDACT='s/^( *pwhash *=).*/\1 "REDACTED"/; s/^( *totp_secret *=).*/\1 "REDACTED"/; s/^( *password *=).*/\1 "REDACTED"/'
|
||||
|
||||
# redact_config <stdin> <stdout> — strip secrets from pihole.toml content
|
||||
redact_config() { sed -E "$REDACT"; }
|
||||
|
||||
# normalize_toml <stdin> <stdout> — redact + drop churn lines (timestamps)
|
||||
normalize_toml() { redact_config | grep -v "Last updated on"; }
|
||||
|
||||
# gen_manifest <dir> — sorted 'md5 name' manifest of *.zone files (name-sorted)
|
||||
gen_manifest() { (cd "$1" && md5sum -- *.zone 2>/dev/null | sort -k2); }
|
||||
|
||||
# fetch <node> <remote-cmd> — run via the remote-dns.sh chokepoint (env IPs honored)
|
||||
fetch() {
|
||||
local node="$1" cmd="$2"
|
||||
bash "$DNS_SETUP/remote-dns.sh" "netinfra${node}-root" "$cmd" 2>/dev/null
|
||||
}
|
||||
|
||||
# check_file <label> <node> <remote-cat-cmd> <local-file> <normalize-fn>
|
||||
check_file() {
|
||||
local label="$1" node="$2" rcmd="$3" local_file="$4" norm="$5" tmp rc
|
||||
tmp="$(mktemp)"
|
||||
fetch "$node" "$rcmd" | "$norm" > "$tmp"
|
||||
if [ ! -s "$tmp" ]; then
|
||||
echo "DRIFT-ERROR: $label: live fetch empty (node $node unreachable?)"
|
||||
rm -f "$tmp"
|
||||
return 2
|
||||
fi
|
||||
"$norm" < "$local_file" | diff -q - "$tmp" >/dev/null 2>&1
|
||||
rc=$?
|
||||
if [ "$rc" -ne 0 ]; then
|
||||
echo "DRIFT: $label (node $node) differs from git: $local_file"
|
||||
"$norm" < "$local_file" | diff - "$tmp" | head -10
|
||||
else
|
||||
echo "OK: $label (node $node) in sync"
|
||||
fi
|
||||
rm -f "$tmp"
|
||||
return "$rc"
|
||||
}
|
||||
|
||||
main() {
|
||||
local nodes="${1:-all}" node rc_total=0 rc
|
||||
[ "$nodes" = "all" ] && nodes="01 02"
|
||||
for node in $nodes; do
|
||||
local_dhcp="$DHCP_DIR/dhcpd-primary.conf"
|
||||
[ "$node" = "02" ] && local_dhcp="$DHCP_DIR/dhcpd-secondary.conf"
|
||||
local_pihole="$PIHOLE_DIR/netinfra-01.pihole.toml"
|
||||
[ "$node" = "02" ] && local_pihole="$PIHOLE_DIR/netinfra-02.pihole.toml"
|
||||
|
||||
check_file "dhcpd.conf" "$node" "cat /etc/dhcp/dhcpd.conf" "$local_dhcp" cat || rc_total=1
|
||||
check_file "pihole.toml" "$node" \
|
||||
"docker exec pihole cat /etc/pihole/pihole.toml" "$local_pihole" normalize_toml || rc_total=1
|
||||
check_file "ntp.conf" "$node" "cat /etc/ntpsec/ntp.conf" "$NTP_FILE" cat || rc_total=1
|
||||
done
|
||||
|
||||
# Technitium zones: binary DZ files, compared by md5 manifest against the
|
||||
# primary (netinfra-01) — the replication source for -02.
|
||||
if [[ "$nodes" == *01* ]]; then
|
||||
remote_manifest="$(fetch 01 "cd $REMOTE_ZONE_DIR && md5sum -- *.zone | sort -k2")"
|
||||
if [ -z "$remote_manifest" ]; then
|
||||
echo "DRIFT-ERROR: technitium zones: live fetch empty (node 01 unreachable?)"
|
||||
rc_total=1
|
||||
else
|
||||
if diff -q <(gen_manifest "$ZONES_DIR") <(printf '%s\n' "$remote_manifest") >/dev/null 2>&1; then
|
||||
echo "OK: technitium zones (node 01) in sync"
|
||||
else
|
||||
echo "DRIFT: technitium zones (node 01) manifest differs from git: $ZONES_DIR"
|
||||
diff <(gen_manifest "$ZONES_DIR") <(printf '%s\n' "$remote_manifest") | head -10
|
||||
rc_total=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [ "$rc_total" -eq 0 ]; then
|
||||
echo "drift-check: ALL IN SYNC"
|
||||
else
|
||||
echo "drift-check: DRIFT DETECTED — reconcile git <-> live before any change"
|
||||
fi
|
||||
return "$rc_total"
|
||||
}
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
||||
node="${2:-all}"
|
||||
[ "${1:-}" = "--node" ] && node="${2:-}" || node="all"
|
||||
main "$node"
|
||||
fi
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/bash
|
||||
#
|
||||
# zone-snapshot.sh — refresh the git SoR snapshot of the Technitium zone
|
||||
# store [#630][#728]
|
||||
#
|
||||
# Pulls the binary DZ zone files from netinfra-01 (the replication primary)
|
||||
# into netinfra/dns/technitium/zones/ via the remote-dns.sh chokepoint, then
|
||||
# shows which snapshot files changed.
|
||||
#
|
||||
# RULE (founder, 2026-09-02): run this after EVERY Technitium record change
|
||||
# and commit the refreshed snapshots in the same session, so the git SoR
|
||||
# never goes stale. netinfra/dns/drift-check.sh verifies the result; the
|
||||
# pre-push rule audit fails on a stale questions file and drift-check is the
|
||||
# DNS counterpart: green before you push any DNS-adjacent change.
|
||||
#
|
||||
# Usage:
|
||||
# zone-snapshot.sh refresh snapshots from the primary
|
||||
# zone-snapshot.sh --check verify only (delegates to drift-check.sh)
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # netinfra/dns/technitium
|
||||
REPO="$(cd "$HERE/../../.." && pwd)"
|
||||
REMOTE_DNS="$HERE/../../dns-cluster-setup/remote-dns.sh"
|
||||
ZONES_DIR="$HERE/zones"
|
||||
REMOTE_ZONE_DIR="/home/localuser/services/technitium/config/zones"
|
||||
|
||||
if [ "${1:-}" = "--check" ]; then
|
||||
exec bash "$HERE/../drift-check.sh"
|
||||
fi
|
||||
|
||||
tmp="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
|
||||
echo "Fetching zone store from netinfra-01 (primary)..."
|
||||
bash "$REMOTE_DNS" netinfra01-root "cd '$REMOTE_ZONE_DIR' && tar cf - *.zone" > "$tmp/zones.tar"
|
||||
|
||||
# Validate the archive before touching the tracked tree.
|
||||
tar -tf "$tmp/zones.tar" >/dev/null
|
||||
|
||||
mkdir -p "$ZONES_DIR"
|
||||
find "$ZONES_DIR" -maxdepth 1 -name '*.zone' -delete
|
||||
tar -xf "$tmp/zones.tar" -C "$ZONES_DIR"
|
||||
|
||||
count="$(find "$ZONES_DIR" -maxdepth 1 -name '*.zone' | wc -l)"
|
||||
echo "Snapshotted $count zone files into ${ZONES_DIR#"$REPO"/}"
|
||||
|
||||
echo "Changed snapshot files (git):"
|
||||
changed="$(git -C "$REPO" status --porcelain -- "$ZONES_DIR")"
|
||||
if [ -n "$changed" ]; then
|
||||
printf '%s\n' "$changed" | sed "s|^$REPO/||" | head -20
|
||||
printf '%s\n' "$changed" | wc -l | xargs -I{} echo "{} files changed — commit these in the same session (DNS sync rule)"
|
||||
else
|
||||
echo " (none — snapshots were already current)"
|
||||
fi
|
||||
|
||||
echo "Verify with: netinfra/dns/drift-check.sh"
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user