refactor: reorganize merged repo into clean directory structure
Reorganize the merged KNELServerBuild + PFVCluster repo:
provisioning/ server provisioning (was ProjectCode/ +
Project-Includes/ + Project-ConfigFiles/)
tests/ test suite (was Project-Tests/)
perf/ Proxmox perf scripts (was top-level *.sh + scripts/)
docs/ all documentation (was ProjectDocs/ + PROJECT.md +
K8S.md + TODO.md)
dns-cluster-setup/ Technitium DNS cluster (unchanged)
netinfra/ netinfra audit scripts (unchanged)
switches/ switch configs (unchanged)
vendor/ vendored KNELShellFramework (unchanged)
Update all internal path references from old directory names
(ProjectCode/, Project-Includes/, Project-Tests/) to the new ones
(provisioning/, tests/) across all scripts.
🤖 Generated with [Crush](https://github.com/charmassociates/crush)
Assisted-by: GLM-5 via Crush <crush@charm.land>
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
#!/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
|
||||
Executable
+142
@@ -0,0 +1,142 @@
|
||||
#!/bin/bash
|
||||
|
||||
# System Requirements Validation Test
|
||||
# Validates minimum system requirements before deployment
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Test configuration
|
||||
MIN_RAM_GB=2
|
||||
MIN_DISK_GB=10
|
||||
REQUIRED_COMMANDS=("curl" "wget" "git" "systemctl" "apt-get")
|
||||
|
||||
# Test functions
|
||||
function test_memory_requirements() {
|
||||
local total_mem_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
||||
local total_mem_gb=$((total_mem_kb / 1024 / 1024))
|
||||
|
||||
if [[ $total_mem_gb -ge $MIN_RAM_GB ]]; then
|
||||
echo "✅ Memory requirement met: ${total_mem_gb}GB >= ${MIN_RAM_GB}GB"
|
||||
return 0
|
||||
else
|
||||
echo "❌ Memory requirement not met: ${total_mem_gb}GB < ${MIN_RAM_GB}GB"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function test_disk_space() {
|
||||
local available_gb=$(df / | tail -1 | awk '{print int($4/1024/1024)}')
|
||||
|
||||
if [[ $available_gb -ge $MIN_DISK_GB ]]; then
|
||||
echo "✅ Disk space requirement met: ${available_gb}GB >= ${MIN_DISK_GB}GB"
|
||||
return 0
|
||||
else
|
||||
echo "❌ Disk space requirement not met: ${available_gb}GB < ${MIN_DISK_GB}GB"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function test_required_commands() {
|
||||
local failed=0
|
||||
|
||||
for cmd in "${REQUIRED_COMMANDS[@]}"; do
|
||||
if command -v "$cmd" >/dev/null 2>&1; then
|
||||
echo "✅ Required command available: $cmd"
|
||||
else
|
||||
echo "❌ Required command missing: $cmd"
|
||||
((++failed))
|
||||
fi
|
||||
done
|
||||
|
||||
return $failed
|
||||
}
|
||||
|
||||
function test_os_compatibility() {
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
local os_id=$(grep "^ID=" /etc/os-release | cut -d'=' -f2 | tr -d '"')
|
||||
local os_version=$(grep "^VERSION_ID=" /etc/os-release | cut -d'=' -f2 | tr -d '"')
|
||||
|
||||
case "$os_id" in
|
||||
ubuntu|debian)
|
||||
echo "✅ OS compatibility: $os_id $os_version (supported)"
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
echo "⚠️ OS compatibility: $os_id $os_version (may work, not fully tested)"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "❌ Cannot determine OS version"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function test_network_connectivity() {
|
||||
local test_urls=(
|
||||
"https://archive.ubuntu.com"
|
||||
"https://linux.dell.com"
|
||||
"https://download.proxmox.com"
|
||||
"https://github.com"
|
||||
)
|
||||
|
||||
local failed=0
|
||||
|
||||
for url in "${test_urls[@]}"; do
|
||||
if curl -s --connect-timeout 10 --max-time 30 "$url" >/dev/null 2>&1; then
|
||||
echo "✅ Network connectivity: $url"
|
||||
else
|
||||
echo "❌ Network connectivity failed: $url"
|
||||
((++failed))
|
||||
fi
|
||||
done
|
||||
|
||||
return $failed
|
||||
}
|
||||
|
||||
function test_permissions() {
|
||||
local test_dirs=("/etc" "/usr/local/bin" "/var/log")
|
||||
local failed=0
|
||||
|
||||
for dir in "${test_dirs[@]}"; do
|
||||
if [[ -w "$dir" ]]; then
|
||||
echo "✅ Write permission: $dir"
|
||||
else
|
||||
echo "❌ Write permission denied: $dir"
|
||||
((++failed))
|
||||
fi
|
||||
done
|
||||
|
||||
return $failed
|
||||
}
|
||||
|
||||
# Main test execution
|
||||
function main() {
|
||||
echo "🔍 Running System Requirements Validation"
|
||||
echo "========================================"
|
||||
|
||||
local total_failures=0
|
||||
|
||||
# Run all validation tests
|
||||
test_memory_requirements || ((total_failures++))
|
||||
test_disk_space || ((total_failures++))
|
||||
test_required_commands || ((total_failures++))
|
||||
test_os_compatibility || ((total_failures++))
|
||||
test_network_connectivity || ((total_failures++))
|
||||
test_permissions || ((total_failures++))
|
||||
|
||||
echo "========================================"
|
||||
|
||||
if [[ $total_failures -eq 0 ]]; then
|
||||
echo "✅ All system requirements validation tests passed"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ $total_failures system requirements validation tests failed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Run main if executed directly
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
main "$@"
|
||||
fi
|
||||
Reference in New Issue
Block a user