watcher: send the inconsistency alert once per disagreement (closes #158)
check / check (push) Failing after 37s
check / check (push) Failing after 37s
detectInconsistencies alerted for every neighbouring pair of nameservers whose records differed, on every DNS check, for as long as they differed. It now also takes the previous hostname state and alerts for a pair only when both nameservers were in that state with equal records. The state loaded at startup is the previous state for the first check, so a disagreement saved before a restart is not reported again. The choice of pairs is in newlyDisagreeingPairs, tested on record data built in the test. The README describes the new behaviour. Model: opus-5-5
This commit is contained in:
+42
-15
@@ -366,7 +366,7 @@ func (w *Watcher) detectHostnameChanges(
|
||||
) {
|
||||
w.detectRecordChanges(ctx, hostname, prev, current)
|
||||
w.detectNSDisappearances(ctx, hostname, prev, current)
|
||||
w.detectInconsistencies(ctx, hostname, current)
|
||||
w.detectInconsistencies(ctx, hostname, prev, current)
|
||||
}
|
||||
|
||||
func (w *Watcher) detectRecordChanges(
|
||||
@@ -448,22 +448,11 @@ func (w *Watcher) detectNSDisappearances(
|
||||
func (w *Watcher) detectInconsistencies(
|
||||
ctx context.Context,
|
||||
hostname string,
|
||||
prev *state.HostnameState,
|
||||
current map[string]map[string][]string,
|
||||
) {
|
||||
nameservers := make([]string, 0, len(current))
|
||||
for ns := range current {
|
||||
nameservers = append(nameservers, ns)
|
||||
}
|
||||
|
||||
sort.Strings(nameservers)
|
||||
|
||||
for i := range len(nameservers) - 1 {
|
||||
ns1 := nameservers[i]
|
||||
ns2 := nameservers[i+1]
|
||||
|
||||
if recordsEqual(current[ns1], current[ns2]) {
|
||||
continue
|
||||
}
|
||||
for _, pair := range newlyDisagreeingPairs(prev, current) {
|
||||
ns1, ns2 := pair[0], pair[1]
|
||||
|
||||
msg := fmt.Sprintf(
|
||||
"Hostname: %s\n%s: %v\n%s: %v",
|
||||
@@ -481,6 +470,44 @@ func (w *Watcher) detectInconsistencies(
|
||||
}
|
||||
}
|
||||
|
||||
// newlyDisagreeingPairs returns the pairs of nameservers, neighbours in
|
||||
// sorted order, whose records differ in current but were equal in prev.
|
||||
// A pair is returned only when both nameservers are in prev, so a
|
||||
// disagreement that was already in prev is not returned again.
|
||||
func newlyDisagreeingPairs(
|
||||
prev *state.HostnameState,
|
||||
current map[string]map[string][]string,
|
||||
) [][2]string {
|
||||
nameservers := make([]string, 0, len(current))
|
||||
for ns := range current {
|
||||
nameservers = append(nameservers, ns)
|
||||
}
|
||||
|
||||
sort.Strings(nameservers)
|
||||
|
||||
var pairs [][2]string
|
||||
|
||||
for i := range len(nameservers) - 1 {
|
||||
ns1 := nameservers[i]
|
||||
ns2 := nameservers[i+1]
|
||||
|
||||
if recordsEqual(current[ns1], current[ns2]) {
|
||||
continue
|
||||
}
|
||||
|
||||
prev1, ok1 := prev.RecordsByNameserver[ns1]
|
||||
prev2, ok2 := prev.RecordsByNameserver[ns2]
|
||||
|
||||
if !ok1 || !ok2 || !recordsEqual(prev1.Records, prev2.Records) {
|
||||
continue
|
||||
}
|
||||
|
||||
pairs = append(pairs, [2]string{ns1, ns2})
|
||||
}
|
||||
|
||||
return pairs
|
||||
}
|
||||
|
||||
func (w *Watcher) checkAllPorts(ctx context.Context) {
|
||||
// Phase 1: Build current IP:port → hostname associations
|
||||
// from fresh DNS data.
|
||||
|
||||
Reference in New Issue
Block a user