Files
PFVCluster/archive/KNELServerBuild/Project-Tests/validation/dns-ntp-redundancy.sh
T
mrcharles 39bb855a98 chore(archive): preserve KNELServerBuild remainder + layout notes [#474]
Archive the non-ported remainder of the legacy KNELServerBuild repo
under archive/KNELServerBuild/ with its original structure intact,
completing the legacy repo merge for everything except the live
LibreNMS patterns (ported in the previous commit).

Exclusions:
- .git history (superseded; legacy repo remains at its original path)
- ported files (Agents/librenms, Modules/OAM/oam-librenms.sh,
  ConfigFiles/SNMP/snmp-sudo.conf)
- vendored KNELShellFramework tree (byte-identical duplicate of the
  copy already vendored at vendor/ in this repo)
- SSH authorized-keys files (live access-control material; carrying
  them in an archive invites drift — key policy lives elsewhere)

The whole tree is skip-listed in tests/shellcheck.sh (archived legacy
code, not maintained — same standing as vendor/); check-rules.sh
already prunes archive/. Rule 9 (conflict markers) now also excludes
archive/ staged files: preserved-verbatim legacy scripts contain
decorative "====" banners that false-positive as conflict markers
(same archive exclusion precedent as rule 11).

AGENTS.md: note archive/KNELServerBuild and oam/librenms-agent in the
Repository Layout, and fix the stale KNELIAC path to
/home/reachableceo/projects/KNEL/KNELIAC.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-08-28 06:12:05 -05:00

203 lines
6.2 KiB
Bash

#!/bin/bash
# Redundant DNS/NTP Validation Test
# Validates that the host is configured to use the redundant pfv-netinfra-01/02
# pair for name resolution and time, and that both servers actually answer.
set -euo pipefail
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
# The authoritative pair (pfv-netinfra-01 / pfv-netinfra-02).
DNS_PRIMARY="192.168.3.252"
DNS_SECONDARY="192.168.3.253"
NTP_PRIMARY="192.168.3.252"
NTP_SECONDARY="192.168.3.253"
RESOLV_CONF="/etc/resolv.conf"
NTP_CONF="/etc/ntpsec/ntp.conf"
# A name every recursive resolver must be able to resolve.
DNS_PROBE_NAME="github.com"
failed=0
have() { command -v "$1" >/dev/null 2>&1; }
# --- Configuration assertions -------------------------------------------------
function test_dns_config_present() {
echo "🔍 Checking $RESOLV_CONF ..."
local problems=0
if [[ -L "$RESOLV_CONF" ]]; then
echo "❌ $RESOLV_CONF is a symlink (would be overwritten by a resolver manager)"
((++problems))
elif [[ ! -f "$RESOLV_CONF" ]]; then
echo "❌ $RESOLV_CONF missing"
((++problems))
fi
for ns in "$DNS_PRIMARY" "$DNS_SECONDARY"; do
if grep -Eq "^[[:space:]]*nameserver[[:space:]]+$ns" "$RESOLV_CONF" 2>/dev/null; then
echo "✅ nameserver $ns configured"
else
echo "❌ nameserver $ns NOT in $RESOLV_CONF"
((++problems))
fi
done
return $problems
}
function test_ntp_config_present() {
echo "🔍 Checking $NTP_CONF ..."
if [[ ! -f "$NTP_CONF" ]]; then
echo "❌ $NTP_CONF missing (is ntpsec installed?)"
return 1
fi
local problems=0
for s in "$NTP_PRIMARY" "$NTP_SECONDARY"; do
if grep -Eq "^[[:space:]]*(server|pool)[[:space:]]+$s" "$NTP_CONF"; then
echo "✅ NTP server $s configured"
else
echo "❌ NTP server $s NOT in $NTP_CONF"
((++problems))
fi
done
return $problems
}
# --- Functional assertions: each server actually answers ----------------------
function _dns_resolves() {
# $1 = server ip. Returns 0 if it resolves DNS_PROBE_NAME.
local server="$1"
if have dig; then
dig @"$server" +short +time=4 +tries=1 "$DNS_PROBE_NAME" A 2>/dev/null | grep -Eq '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'
elif have nslookup; then
nslookup "$DNS_PROBE_NAME" "$server" 2>/dev/null | grep -Eq 'Address:[[:space:]]*[0-9]'
elif have host; then
host "$DNS_PROBE_NAME" "$server" 2>/dev/null | grep -Eq 'has address'
else
# Last resort: the resolver itself.
getent ahostsv4 "$DNS_PROBE_NAME" >/dev/null 2>&1
fi
}
function test_dns_servers_answer() {
echo "🔍 Probing DNS servers ..."
local problems=0
for ns in "$DNS_PRIMARY" "$DNS_SECONDARY"; do
if _dns_resolves "$ns"; then
echo "✅ $ns resolves $DNS_PROBE_NAME"
else
echo "❌ $ns did not resolve $DNS_PROBE_NAME"
((++problems))
fi
done
return $problems
}
function _ntp_answers() {
# $1 = server ip. Returns 0 if it responds to a time query.
local server="$1"
if have ntpdate; then
timeout 8 ntpdate -q "$server" 2>/dev/null | grep -Eq 'no-leap|leap'
elif have sntp; then
timeout 8 sntp -t 4 "$server" >/dev/null 2>&1
elif have chronyc; then
# NTS/chrony not expected here, but be tolerant.
chronyc -n -h "$server" tracking >/dev/null 2>&1
else
return 2 # cannot test
fi
}
function test_ntp_servers_answer() {
echo "🔍 Probing NTP servers ..."
local problems=0
for s in "$NTP_PRIMARY" "$NTP_SECONDARY"; do
if _ntp_answers "$s"; then
echo "✅ NTP $s responds to time query"
else
echo "❌ $s did not respond to NTP query"
((++problems))
fi
done
return $problems
}
# --- End-to-end: the host is actually USING the pair --------------------------
function test_resolver_endtoend() {
echo "🔍 End-to-end resolution via $RESOLV_CONF ..."
if getent ahostsv4 "$DNS_PROBE_NAME" >/dev/null 2>&1; then
echo "✅ Host resolves $DNS_PROBE_NAME via configured resolver"
return 0
else
echo "❌ Host cannot resolve $DNS_PROBE_NAME via configured resolver"
return 1
fi
}
function test_ntp_daemon_peers() {
echo "🔍 NTP daemon peer list ..."
local peers
if have ntpq; then
peers="$(ntpq -pn 2>/dev/null || true)"
elif have chronyc; then
peers="$(chronyc -n sources 2>/dev/null || true)"
else
echo "⚠️ No ntpq/chronyc available; skipping daemon peer check"
return 0
fi
local problems=0
for s in "$NTP_PRIMARY" "$NTP_SECONDARY"; do
if echo "$peers" | grep -Eq "^\\s*${s//./\\.}"; then
echo "✅ NTP daemon has peer $s"
else
echo "❌ NTP daemon is NOT tracking $s"
((++problems))
fi
done
# Sync status is informational only: a freshly started daemon needs several
# polls before the reach counter stabilises, so we warn rather than fail.
if echo "$peers" | grep -Eq '\*'; then
echo "✅ NTP daemon reports a synced peer"
else
echo "⚠️ NTP daemon not yet synced (normal for a few minutes after restart)"
fi
return $problems
}
# --- Main ---------------------------------------------------------------------
function main() {
echo "🛰️ Running Redundant DNS/NTP Validation Tests"
echo "================================================"
local total_failures=0
test_dns_config_present || ((++total_failures))
test_ntp_config_present || ((++total_failures))
test_dns_servers_answer || ((++total_failures))
test_ntp_servers_answer || ((++total_failures))
test_resolver_endtoend || ((++total_failures))
test_ntp_daemon_peers || ((++total_failures))
echo "================================================"
if [[ $total_failures -eq 0 ]]; then
echo "✅ All redundant DNS/NTP validation tests passed"
exit 0
else
echo "❌ $total_failures redundant DNS/NTP tests failed"
exit 1
fi
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi