apply records before the apex NS, so in-zone glue exists first
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful

named rejects an apex NS pointing at an in-zone name with no address record,
so the glue has to land in an earlier transaction.
This commit is contained in:
2026-09-26 19:41:53 +10:00
parent 08d46ccce0
commit cc714dc2b4
4 changed files with 63 additions and 28 deletions
+13 -6
View File
@@ -52,15 +52,22 @@ func (e *Executor) ApexNS(ctx context.Context, namespace, pod, zone string, cred
if err != nil {
return nil, fmt.Errorf("query apex NS of %s: %w (out: %s)", zone, err, out)
}
var ns []string
return parseDigNames(out), nil
}
// parseDigNames picks the answers out of `dig +short` output: one fully-qualified
// name per line. Anything without a trailing dot is not a name, and dig prefixes
// its diagnostics (a missing or mismatched TSIG key among them) with ';'.
func parseDigNames(out string) []string {
var names []string
for _, line := range strings.Split(out, "\n") {
// dig +short prints one fully-qualified name per line; anything without a
// trailing dot is not an answer.
if line = strings.TrimSpace(line); strings.HasSuffix(line, ".") {
ns = append(ns, line)
line = strings.TrimSpace(line)
if strings.HasPrefix(line, ";") || !strings.HasSuffix(line, ".") {
continue
}
names = append(names, line)
}
return ns, nil
return names
}
// nsupdateScript renders the nsupdate input for a set of changes.
+23 -1
View File
@@ -1,6 +1,9 @@
package bind
import "testing"
import (
"strings"
"testing"
)
func TestNSUpdateScriptReplaceSemantics(t *testing.T) {
got := nsupdateScript("acme.unkin.net", []RecordUpdate{
@@ -40,3 +43,22 @@ send
t.Errorf("got:\n%s\nwant:\n%s", got, want)
}
}
func TestParseDigNames(t *testing.T) {
cases := []struct {
name, out, want string
}{
{"answers", "a.ns.unkin.net.\nb.ns.unkin.net.\n", "a.ns.unkin.net.,b.ns.unkin.net."},
{"REFUSED, SERVFAIL and NXDOMAIN all answer empty", "", ""},
// A zone behind a key-matched view answers an unsigned query REFUSED, and
// dig reports the key problem on a ';' line that happens to end in a dot.
{"dig diagnostics are not answers", ";; WARNING -- TSIG key was not used.\n", ""},
{"relative or partial lines are not names", "10.0.0.1\nns1\n", ""},
{"whitespace is trimmed", " ns1.unkin.net. \n\n", "ns1.unkin.net."},
}
for _, c := range cases {
if got := strings.Join(parseDigNames(c.out), ","); got != c.want {
t.Errorf("%s: parseDigNames(%q) = %q; want %q", c.name, c.out, got, c.want)
}
}
}