diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7f1b219..8e21f66 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -59,6 +59,9 @@ jobs: - name: test_hostname_filter.sh run: bash hosting-panels/common/tests/test_hostname_filter.sh + - name: test_pdns_restart.sh + run: bash hosting-panels/common/tests/test_pdns_restart.sh + - name: test_cyberpanel_db.sh run: bash hosting-panels/common/tests/test_cyberpanel_db.sh diff --git a/hosting-panels/common/tests/test_pdns_restart.sh b/hosting-panels/common/tests/test_pdns_restart.sh new file mode 100755 index 0000000..b353481 --- /dev/null +++ b/hosting-panels/common/tests/test_pdns_restart.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# PowerDNS rereads zones on a reload but not allow-axfr-ips, so a reload after +# editing pdns.conf leaves AXFR refused and every zone stuck pending. +# Run: bash hosting-panels/common/tests/test_pdns_restart.sh +set -u +HERE="$(cd "$(dirname "$0")" && pwd)" +PANELS="cpanel cyberpanel directadmin plesk" +PASS=0; FAIL=0 +ok() { PASS=$((PASS+1)); echo " ok: $1"; } +fail() { FAIL=$((FAIL+1)); echo " FAIL: $1"; } + +checked=0 +for panel in $PANELS; do + src="$HERE/../../$panel/install.sh" + [ -f "$src" ] || { echo "missing $src"; exit 1; } + grep -q "pdns" "$src" || continue + checked=$((checked+1)) + echo "== $panel" + + if grep -qE "systemctl reload pdns|pdns_control reload|service pdns reload" "$src"; then + fail "reloads PowerDNS after editing pdns.conf" + else + ok "no PowerDNS reload" + fi + + # editing the config at all obliges a restart + if grep -q 'allow-axfr-ips' "$src"; then + grep -qE "(systemctl|service) .*pdns.* restart|systemctl restart pdns" "$src" \ + && ok "restarts PowerDNS" || fail "edits allow-axfr-ips without restarting" + # a restart that does not come back must not be reported as success: + # the config is restored and the operator told, not a cheerful "[+]" + grep -q 'did not come back' "$src" \ + && ok "reports a PowerDNS that stayed down" || fail "a dead PowerDNS would be reported as success" + grep -qE 'cp "[^"]*(BAK|bak)[^"]*" "\$PDNS_CONF"' "$src" \ + && ok "restores the config on a failed restart" || fail "no rollback on a failed restart" + fi +done + +# a lower bound: a rename that stops matching the installers fails here +[ "$checked" -ge 3 ] && ok "checked $checked installers" || fail "only $checked installers matched" + +echo +echo "passed=$PASS failed=$FAIL" +[ "$FAIL" -eq 0 ] diff --git a/hosting-panels/cpanel/install.sh b/hosting-panels/cpanel/install.sh index 0d5ca92..fbc37ea 100755 --- a/hosting-panels/cpanel/install.sh +++ b/hosting-panels/cpanel/install.sh @@ -351,7 +351,8 @@ else if [ ! -f "$PDNS_CONF" ]; then echo "[!] pdns.conf not found at $PDNS_CONF — configure AXFR manually" else - cp "$PDNS_CONF" "${PDNS_CONF}.bak.$(date +%s)" + PDNS_BAK="${PDNS_CONF}.bak.$(date +%s)" + cp "$PDNS_CONF" "$PDNS_BAK" # primary / master mode (name differs by pdns version) if grep -q "^master=" "$PDNS_CONF" 2>/dev/null; then @@ -401,13 +402,19 @@ else echo "[+] PowerDNS: also-notify=$SECONDARY_IP" fi - # Reload - if systemctl reload pdns &>/dev/null 2>&1; then - echo "[+] PowerDNS reloaded" - elif pdns_control reload &>/dev/null 2>&1; then - echo "[+] PowerDNS reloaded via pdns_control" + # A reload rereads the zones, not the settings above: allow-axfr-ips + # only takes effect on a restart, and until then AXFR is refused. + systemctl restart pdns 2>/dev/null || service pdns restart 2>/dev/null + sleep 2 + if systemctl is-active --quiet pdns 2>/dev/null || pgrep -x pdns_server >/dev/null; then + echo "[+] PowerDNS configured and restarted" else - echo "[!] Restart PowerDNS manually: systemctl restart pdns" + # Saying "OK" while the DNS server is down is worse than + # failing: restore what was there and let a human look. + [ -n "${PDNS_BAK:-}" ] && cp "$PDNS_BAK" "$PDNS_CONF" + systemctl restart pdns 2>/dev/null || service pdns restart 2>/dev/null + echo "[!] PowerDNS did not come back — configuration restored from the backup" + echo "[!] Check: journalctl -u pdns -n 20" fi fi diff --git a/hosting-panels/directadmin/install.sh b/hosting-panels/directadmin/install.sh index eb3669e..94c3d27 100644 --- a/hosting-panels/directadmin/install.sh +++ b/hosting-panels/directadmin/install.sh @@ -344,7 +344,8 @@ if [ -n "$DNS_IPS" ]; then if [ "$ISSUES" -gt 0 ]; then if confirm "Apply PowerDNS fixes automatically? (backup will be created)"; then - cp "$PDNS_CONF" "${PDNS_CONF}.bak.$(date +%s)" + PDNS_BAK="${PDNS_CONF}.bak.$(date +%s)" + cp "$PDNS_CONF" "$PDNS_BAK" grep -qE "^master=yes" "$PDNS_CONF" || echo "master=yes" >> "$PDNS_CONF" grep -qE "^default-soa-edit=" "$PDNS_CONF" || echo "default-soa-edit=INCEPTION-INCREMENT" >> "$PDNS_CONF" @@ -364,7 +365,17 @@ if [ -n "$DNS_IPS" ]; then fi systemctl restart pdns 2>/dev/null || service pdns restart 2>/dev/null - echo "[+] PowerDNS configured and restarted" + sleep 2 + if systemctl is-active --quiet pdns 2>/dev/null || pgrep -x pdns_server >/dev/null; then + echo "[+] PowerDNS configured and restarted" + else + # Saying "OK" while the DNS server is down is worse than + # failing: restore what was there and let a human look. + cp "$PDNS_BAK" "$PDNS_CONF" + systemctl restart pdns 2>/dev/null || service pdns restart 2>/dev/null + echo "[!] PowerDNS did not come back — configuration restored from the backup" + echo "[!] Check: journalctl -u pdns -n 20" + fi fi else echo "[+] PowerDNS AXFR config OK"