diff --git a/checker/report.go b/checker/report.go index ed7d851..572d952 100644 --- a/checker/report.go +++ b/checker/report.go @@ -116,7 +116,7 @@ type regionRow struct { Reachable int Agreeing int Disagreeing int - Errored int + Unreachable int } type resolverRow struct { @@ -283,28 +283,32 @@ func buildReportView(d *ResolverPropagationData, findings []Finding) *reportView r.Resolvers++ if rv.Reachable { r.Reachable++ + } else { + r.Unreachable++ } if rv.Reachable && !rv.Filtered { - ok := true + unreachableProbe := false + disagrees := false for key, p := range rv.Probes { if p == nil || p.Error != "" { - r.Errored++ - ok = false - break + unreachableProbe = true + continue } cv := d.RRsets[key] if cv == nil || cv.ConsensusSig == "" { continue } if p.Signature != cv.ConsensusSig { - ok = false - break + disagrees = true } } - if ok { - r.Agreeing++ - } else { + switch { + case disagrees: r.Disagreeing++ + case unreachableProbe: + r.Unreachable++ + default: + r.Agreeing++ } } } @@ -664,7 +668,7 @@ const reportTemplateHTML = `

Per-region view

- + {{range .Regions}} @@ -672,7 +676,7 @@ const reportTemplateHTML = ` - + {{end}} @@ -690,7 +694,7 @@ const reportTemplateHTML = ` - +
RegionReachableAgreeingDisagreeingErrored
RegionReachableAgreeingDisagreeingUnreachable
{{.Reachable}} / {{.Resolvers}} {{.Agreeing}} {{if .Disagreeing}}{{.Disagreeing}}{{else}}0{{end}}{{if .Errored}}{{.Errored}}{{else}}0{{end}}{{if .Unreachable}}{{.Unreachable}}{{else}}0{{end}}
{{.Region}} {{.Transport}}{{if .Reachable}}{{.AvgMs}}{{else}}unreachable{{end}}{{if .Reachable}}{{.AvgMs}}{{else}}unreachable{{end}} {{range .Probes}}
diff --git a/checker/rules.go b/checker/rules.go index 9ef20bf..6c7d822 100644 --- a/checker/rules.go +++ b/checker/rules.go @@ -57,3 +57,7 @@ func warnState(code, subject, message string) sdk.CheckState { func critState(code, subject, message string) sdk.CheckState { return sdk.CheckState{Status: sdk.StatusCrit, Message: message, Code: code, Subject: subject} } + +func unknownState(code, subject, message string) sdk.CheckState { + return sdk.CheckState{Status: sdk.StatusUnknown, Message: message, Code: code, Subject: subject} +} diff --git a/checker/rules_consensus.go b/checker/rules_consensus.go index eb45834..3f7ff96 100644 --- a/checker/rules_consensus.go +++ b/checker/rules_consensus.go @@ -91,8 +91,8 @@ func (r *authoritativeMatchRule) Evaluate(ctx context.Context, obs sdk.Observati anyExpected = true switch { case v.ConsensusSig == "": - states = append(states, critState("resolver_propagation.matches_authoritative.no_consensus", key, - fmt.Sprintf("no public resolver returned a usable answer for %s (authoritative answer is known)", key))) + states = append(states, unknownState("resolver_propagation.matches_authoritative.no_consensus", key, + fmt.Sprintf("no public resolver returned a usable answer for %s (authoritative answer is known); resolvers unreachable from the checker", key))) case !v.MatchesExpected: states = append(states, critState(CodeAnswerDrift, key, fmt.Sprintf("consensus of public resolvers for %s differs from the authoritative answer, wait for TTL expiry or force a flush", key))) diff --git a/checker/rules_resolvers.go b/checker/rules_resolvers.go index 8fa8b17..995140d 100644 --- a/checker/rules_resolvers.go +++ b/checker/rules_resolvers.go @@ -71,7 +71,7 @@ func (r *resolverLatencyRule) Evaluate(ctx context.Context, obs sdk.ObservationG var states []sdk.CheckState for _, rv := range data.Resolvers { if !rv.Reachable { - states = append(states, warnState(CodeResolverUnreachable, rv.ID, + states = append(states, unknownState(CodeResolverUnreachable, rv.ID, fmt.Sprintf("resolver %s (%s, %s) did not answer any query", rv.Name, rv.IP, rv.Transport))) continue } diff --git a/checker/rules_test.go b/checker/rules_test.go index e14d999..1007fc7 100644 --- a/checker/rules_test.go +++ b/checker/rules_test.go @@ -326,8 +326,11 @@ func TestResolverLatencyRule(t *testing.T) { if _, ok := codes[CodeResolverHighLatency]; !ok { t.Errorf("want high latency for 'slow', got %+v", st) } - if _, ok := codes[CodeResolverUnreachable]; !ok { + unreach, ok := codes[CodeResolverUnreachable] + if !ok { t.Errorf("want unreachable for 'absent', got %+v", st) + } else if unreach[0].Status != sdk.StatusUnknown { + t.Errorf("unreachable should be unknown (not a warning), got status %v", unreach[0].Status) } }