check / check (push) Successful in 1m37s
LookupAllRecords now returns each nameserver's response, so the watcher saves its status: ok when it answered, NXDOMAIN and no records included, and error with the reason when it timed out, answered SERVFAIL or REFUSED, or could not be reached. A nameserver that starts failing sends NS Failure and one that answers again sends NS Recovery. A failing nameserver is left out of the record change and inconsistency comparisons. The resolver used to report REFUSED and network errors as an answer with no records; they are now errors. A lookup cut short by its context now returns an error instead of a failure of the nameserver it was querying. Model: opus-5-5
58 lines
1.3 KiB
Go
58 lines
1.3 KiB
Go
package watcher
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"time"
|
|
|
|
"sneak.berlin/go/dnswatcher/internal/config"
|
|
"sneak.berlin/go/dnswatcher/internal/resolver"
|
|
"sneak.berlin/go/dnswatcher/internal/state"
|
|
)
|
|
|
|
// NewForTest creates a Watcher without fx for unit testing.
|
|
func NewForTest(
|
|
cfg *config.Config,
|
|
st *state.State,
|
|
res DNSResolver,
|
|
pc PortChecker,
|
|
tc TLSChecker,
|
|
n Notifier,
|
|
) *Watcher {
|
|
return &Watcher{
|
|
log: slog.Default(),
|
|
config: cfg,
|
|
state: st,
|
|
resolver: res,
|
|
portCheck: pc,
|
|
tlsCheck: tc,
|
|
notify: n,
|
|
firstRun: true,
|
|
expiryNotified: make(map[string]time.Time),
|
|
}
|
|
}
|
|
|
|
// NewlyDisagreeingPairs exports newlyDisagreeingPairs for testing.
|
|
func NewlyDisagreeingPairs(
|
|
prev, current *state.HostnameState,
|
|
) [][2]string {
|
|
return newlyDisagreeingPairs(prev, current)
|
|
}
|
|
|
|
// DetectHostnameChanges exports detectHostnameChanges for testing.
|
|
func (w *Watcher) DetectHostnameChanges(
|
|
ctx context.Context,
|
|
hostname string,
|
|
prev, current *state.HostnameState,
|
|
) {
|
|
w.detectHostnameChanges(ctx, hostname, prev, current)
|
|
}
|
|
|
|
// BuildHostnameState exports buildHostnameState for testing.
|
|
func BuildHostnameState(
|
|
results map[string]*resolver.NameserverResponse,
|
|
now time.Time,
|
|
) *state.HostnameState {
|
|
return buildHostnameState(results, now)
|
|
}
|