package checker import ( "encoding/json" "fmt" "html/template" "strings" sdk "git.happydns.org/checker-sdk-go/checker" ) // reportData is the view-model fed to the HTML template. type reportData struct { ServiceDomain string Records []reportRecord // Top-level alerts: the most common / most actionable failure scenarios, // surfaced at the top of the report with remediation guidance. Alerts []reportAlert Totals reportTotals } type reportRecord struct { Owner string Service string Proto string Target string Port uint16 Priority uint16 Weight uint16 IsNullTarget bool IsCNAME bool CNAMEChain string Addresses []string ResolveError string Probes []reportProbe } type reportProbe struct { Address string Proto string Connected bool LatencyMs float64 Error string StatusClass string StatusLabel string } type reportAlert struct { Severity string // "crit", "warn", "info" Title string Body template.HTML } type reportTotals struct { Records int OKProbes int BadProbes int } var htmlTpl = template.Must(template.New("srv").Parse(`
{{.ServiceDomain}}{{else}}service{{end}}CNAME chain: {{.CNAMEChain}} — RFC 2782 forbids a CNAME as SRV target.
Resolution failed: {{.ResolveError}}
{{end}} {{if .Addresses}}Resolves to: {{range .Addresses}}{{.}} {{end}}
| Address | Proto | Status | Latency | Details |
|---|---|---|---|---|
{{.Address}} |
{{.Proto}} | {{.StatusLabel}} | {{if .LatencyMs}}{{printf "%.1f ms" .LatencyMs}}{{end}} | {{if .Error}}{{.Error}}{{end}} |
"+strings.Join(cnames, ", ")+"")),
})
}
if len(tcpDown) > 0 {
var items []string
for a, e := range tcpDown {
items = append(items, fmt.Sprintf("%s: %s", a, e))
}
rd.Alerts = append(rd.Alerts, reportAlert{
Severity: "crit",
Title: fmt.Sprintf("%d target(s) unreachable on their advertised TCP port", len(tcpDown)),
Body: template.HTML(strings.Join(items, "\".\" to signal that the service is " +
"intentionally not available. If this is what you want, the configuration is correct. " +
"If you expected clients to reach this service, replace the null target with a real hostname."),
})
}
var buf strings.Builder
if err := htmlTpl.Execute(&buf, rd); err != nil {
return "", fmt.Errorf("failed to render SRV HTML report: %w", err)
}
return buf.String(), nil
}