watcher: a removed nameserver is an NS Change, not an NS Failure (closes #262)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
A nameserver that left a domain's delegation was reported twice: as the domain's NS Change, and by the check of the domain's own records as an error-level NS Failure saying it disappeared. That check now sends nothing for a domain. For a hostname, the nameservers that leave its zone are sent as one NS Change at warning level, with a Hostname: line and a Removed: line, as decided on the issue; nothing is sent for one that joins. The README says what each case gets. A nameserver that was failing before it left is now listed too; the NS Failure skipped it. A domain with no delegation of its own gets nothing when a nameserver leaves the zone it is in. Model: opus-5-5
This commit is contained in:
@@ -81,14 +81,12 @@ func TestDomainRecordNotificationsNameTheDomain(t *testing.T) {
|
||||
)
|
||||
|
||||
// nsA's address changes, which also makes it differ from nsC; nsB
|
||||
// fails; nsC answers again; nsD is gone.
|
||||
nsD := "d.ns.example.net."
|
||||
// fails; nsC answers again.
|
||||
w.DetectHostnameChanges(t.Context(), domain,
|
||||
saved(map[string]*state.NameserverRecordState{
|
||||
nsA: answered(map[string][]string{"A": {ip1}}),
|
||||
nsB: answered(map[string][]string{"A": {ip1}}),
|
||||
nsC: failed(),
|
||||
nsD: answered(map[string][]string{"A": {ip1}}),
|
||||
}),
|
||||
saved(map[string]*state.NameserverRecordState{
|
||||
nsA: answered(map[string][]string{"A": {ip2}}),
|
||||
@@ -102,11 +100,10 @@ func TestDomainRecordNotificationsNameTheDomain(t *testing.T) {
|
||||
t.Context(), domain, cnameState(ip1), cnameState(ip2),
|
||||
)
|
||||
|
||||
// NS Failure is sent for nsB failing and for nsD being gone.
|
||||
want := map[string]int{
|
||||
"Record Change": 1,
|
||||
"Inconsistency": 1,
|
||||
"NS Failure": 2,
|
||||
"NS Failure": 1,
|
||||
"NS Recovery": 1,
|
||||
"CNAME Address Change": 1,
|
||||
}
|
||||
@@ -128,6 +125,41 @@ func TestDomainRecordNotificationsNameTheDomain(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// nsB, which answered, and nsC, which did not, are no longer among the
|
||||
// nameservers. For the hostname one NS Change lists both; for the
|
||||
// configured apex domain nothing is sent, because the check of its
|
||||
// delegation sends its NS Change.
|
||||
func TestRemovedNameserversAreAnNSChange(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
notifier := &mockNotifier{}
|
||||
w := watcher.NewForTest(
|
||||
&config.Config{Domains: []string{domain}},
|
||||
nil, nil, nil, nil, notifier,
|
||||
)
|
||||
|
||||
prev := saved(map[string]*state.NameserverRecordState{
|
||||
nsA: answered(map[string][]string{"A": {ip1}}),
|
||||
nsB: answered(map[string][]string{"A": {ip1}}),
|
||||
nsC: failed(),
|
||||
})
|
||||
current := saved(map[string]*state.NameserverRecordState{
|
||||
nsA: answered(map[string][]string{"A": {ip1}}),
|
||||
})
|
||||
|
||||
w.DetectHostnameChanges(t.Context(), domain, prev, current)
|
||||
w.DetectHostnameChanges(t.Context(), host, prev, current)
|
||||
|
||||
title := "NS Change: " + host
|
||||
want := `Hostname: www.example.net
|
||||
Removed: b.ns.example.net., c.ns.example.net.`
|
||||
|
||||
got := notifier.getNotifications()
|
||||
if len(got) != 1 || got[0].Title != title || got[0].Message != want {
|
||||
t.Errorf("sent %v, want one %q with message:\n%s", got, title, want)
|
||||
}
|
||||
}
|
||||
|
||||
// The startup notification counts the configured domains and hostnames,
|
||||
// although the state's hostnames also hold the apex domain's own
|
||||
// records. Nothing is looked up: the watcher has no resolver.
|
||||
|
||||
Reference in New Issue
Block a user