Linked zones: PTR records follow each view, deleting an override stays deleted

Auto-PTR (and --ptr) changed PTR records in every linked view, whatever
view the address record was in. ptrSync now compares each touched A/AAAA
set before and after, per view, and changes only that view's reverse
zone. PTR records in linked reverse zones are local (fill too); a shared
PTR set is made local in each view before one view changes it.

Deleting a linked zone's local records no longer brings the shared ones
back into the view: the name and type are gone from that view and the
other views keep theirs, local to each. Share still restores.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adamandClaude Opus 5.5 committed 2026-10-18 15:29:12 +01:00
1 parent e38390df7d
commit 65086e314a
9 files changed
+453 -238

No files matched your search

+30 -3
View File
@@ -130,10 +130,15 @@ func TestLinkedZones(t *testing.T) {
if !slices.Contains(env.view("external"), "www A 192.0.2.11 S") || slices.Contains(env.view("internal"), "www A 192.0.2.11 S") {
t.Errorf("shared set with an override elsewhere: internal %q external %q", env.view("internal"), env.view("external"))
}
// Removing the override brings the shared records back.
// Removing the override removes www A from internal only: external
// keeps its record, local now. Sharing it brings it back to internal.
env.submit(env.admin, NewRequest(OpRRSetReplace, 0, RRSetInput{Zone: "example.com", View: "internal", Name: "www", Type: "A", Data: []string{}}))
if !slices.Contains(env.view("internal"), "www A 192.0.2.11 S") {
t.Errorf("override removed: internal %q", env.view("internal"))
if slices.ContainsFunc(env.view("internal"), func(s string) bool { return strings.HasPrefix(s, "www A ") }) || !slices.Contains(env.view("external"), "www A 192.0.2.11 L") {
t.Errorf("override removed: internal %q external %q", env.view("internal"), env.view("external"))
}
env.submit(env.admin, NewRequest(OpRecordUpdate, env.recordID("external", "www", "A"), RecordInput{Local: model.Ptr(false)}))
if !slices.Contains(env.view("internal"), "www A 192.0.2.11 S") || !slices.Contains(env.view("external"), "www A 192.0.2.11 S") {
t.Errorf("shared again: internal %q external %q", env.view("internal"), env.view("external"))
}
// Make a shared set local, then share another view's version.
@@ -386,3 +391,25 @@ func TestCompareReport(t *testing.T) {
t.Errorf("mail A: %+v", rep)
}
}
// A shared record made local in one view, then deleted there, is gone from
// that view only; the other view keeps it, local now.
func TestDeleteLocalOverride(t *testing.T) {
env := linkedEnv(t)
env.submit(env.admin, NewRequest(OpZoneCreate, 0, ZoneInput{Name: model.Ptr("example.com"), View: model.Ptr("external"), LinkWith: "internal"}))
env.submit(env.admin, recIn("internal", "a", "A", "192.0.2.50"))
if !slices.Contains(env.view("external"), "a A 192.0.2.50 S") {
t.Fatalf("not shared: %q", env.view("external"))
}
env.submit(env.admin, NewRequest(OpRecordUpdate, env.recordID("internal", "a", "A"), RecordInput{Local: model.Ptr(true)}))
env.submit(env.admin, NewRequest(OpRecordDelete, env.recordID("internal", "a", "A"), nil))
if slices.ContainsFunc(env.view("internal"), func(s string) bool { return strings.HasPrefix(s, "a A ") }) {
t.Errorf("internal still has a: %q", env.view("internal"))
}
if !slices.Contains(env.view("external"), "a A 192.0.2.50 L") {
t.Errorf("external: %q", env.view("external"))
}
if probs := env.e.Validate(env.state()); hasCode(probs, "linked_out_of_sync") || hasCode(probs, "linked_mixed") {
t.Errorf("validation: %+v", probs)
}
}