From f20b26fd712c9247133ca0e5b8da052363f49ffa Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Sat, 8 Aug 2026 22:38:20 +1000 Subject: [PATCH] Wait for HA peer DNS before starting kea-dhcp4 ## Why kea-dhcp4 crash-loops on a cold container start: the HA hook resolves the StatefulSet peer URL hostnames once at config load, but the peer DNS records are not resolvable in the first moment of a fresh container, and kea exits hard instead of retrying (HA_CONFIGURATION_FAILED / "Failed to convert string to address"). Once DNS is warm the exact config validates, so the failure is purely a startup race. ## How - gate the dhcp4 entrypoint on `kea-dhcp4 -t` and retry until the config validates before exec'ing the server --- internal/kea/agent.go | 9 +++++++++ internal/kea/config_test.go | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/internal/kea/agent.go b/internal/kea/agent.go index 273f1c3..e5b848c 100644 --- a/internal/kea/agent.go +++ b/internal/kea/agent.go @@ -37,6 +37,15 @@ ORD="${HOSTNAME##*-}" mkdir -p %[1]s chmod 0750 %[1]s sed "s/%[2]s/server${ORD}/g" %[3]s/kea-dhcp4.conf > %[4]s +# The HA hook resolves peer URL hostnames once at load; on a cold container +# start the StatefulSet peer DNS records may not resolve yet, and kea exits +# hard instead of retrying. Wait for the config to validate before starting. +i=0 +until %[5]s -t %[4]s >/dev/null 2>&1; do + i=$((i+1)) + if [ "$i" -ge 60 ]; then break; fi + sleep 2 +done exec %[5]s -c %[4]s `, RunDir, ThisServerPlaceholder, ConfigDir, DHCP4ConfPath, DHCP4Bin) } diff --git a/internal/kea/config_test.go b/internal/kea/config_test.go index 47bc01a..396296d 100644 --- a/internal/kea/config_test.go +++ b/internal/kea/config_test.go @@ -249,6 +249,17 @@ func TestEntrypointsHardenSocketDir(t *testing.T) { } } +func TestEntrypointWaitsForConfigToValidate(t *testing.T) { + // The dhcp4 entrypoint must gate startup on `kea-dhcp4 -t` so a cold-start + // HA peer DNS resolution failure retries instead of crash-looping. + ep := EntrypointDHCP4() + for _, want := range []string{"until " + DHCP4Bin + " -t " + DHCP4ConfPath, "exec " + DHCP4Bin + " -c " + DHCP4ConfPath} { + if !strings.Contains(ep, want) { + t.Errorf("dhcp4 entrypoint must contain %q, got:\n%s", want, ep) + } + } +} + func TestControlSocketPathAllowedByKea(t *testing.T) { if !strings.HasPrefix(CtrlSocketPath, "/var/run/kea/") { t.Errorf("CtrlSocketPath %q must live under /var/run/kea (kea 2.6+ restriction)", CtrlSocketPath) -- 2.47.3