diff --git a/checker/report.go b/checker/report.go
index 8cdb3c2..5d44efb 100644
--- a/checker/report.go
+++ b/checker/report.go
@@ -256,52 +256,79 @@ func (p *srvProvider) GetHTMLReport(ctx sdk.ReportContext) (string, error) {
rd.Records = append(rd.Records, rec)
}
- if len(resolveFails) > 0 {
- rd.Alerts = append(rd.Alerts, reportAlert{
- Severity: "crit",
- Title: fmt.Sprintf("DNS resolution failed for %d SRV target(s)", len(resolveFails)),
- Body: template.HTML(fmt.Sprintf(
- "%s
Clients will not be able to reach the service. Fix: either publish A/AAAA records for the target(s), or remove the broken SRV record.",
- strings.Join(resolveFails, "
"))),
- })
- }
- if len(cnames) > 0 {
- rd.Alerts = append(rd.Alerts, reportAlert{
- Severity: "warn",
- Title: "SRV target is a CNAME (RFC 2782 violation)",
- Body: template.HTML(fmt.Sprintf(
- "Target(s): %s
RFC 2782 requires SRV targets to resolve directly to A/AAAA. "+
- "Some clients will refuse to follow the CNAME. Fix: point the SRV record to a hostname with A/AAAA records, "+
- "or replace the CNAME with an ALIAS/ANAME at the DNS provider.",
- ""+strings.Join(cnames, ", ")+"")),
- })
- }
- if len(tcpDown) > 0 {
- var items []string
- for _, f := range tcpDown {
- items = append(items, fmt.Sprintf("%s (%s): %s",
- template.HTMLEscapeString(f.address),
- template.HTMLEscapeString(f.owner),
- template.HTMLEscapeString(f.err)))
+ // Build alerts from rule states when available; fall back to raw-data
+ // analysis when the host hasn't threaded rule output through yet.
+ states := ctx.States()
+ if len(states) > 0 {
+ for _, st := range states {
+ sev := ""
+ switch st.Status {
+ case sdk.StatusCrit, sdk.StatusError:
+ sev = "crit"
+ case sdk.StatusWarn:
+ sev = "warn"
+ case sdk.StatusInfo:
+ sev = "info"
+ default:
+ continue
+ }
+ alert := reportAlert{
+ Severity: sev,
+ Title: st.Message,
+ }
+ if fix, ok := st.Meta["fix"].(string); ok && fix != "" {
+ alert.Body = template.HTML(template.HTMLEscapeString(fix))
+ }
+ rd.Alerts = append(rd.Alerts, alert)
+ }
+ } else {
+ if len(resolveFails) > 0 {
+ rd.Alerts = append(rd.Alerts, reportAlert{
+ Severity: "crit",
+ Title: fmt.Sprintf("DNS resolution failed for %d SRV target(s)", len(resolveFails)),
+ Body: template.HTML(fmt.Sprintf(
+ "%s
Clients will not be able to reach the service. Fix: either publish A/AAAA records for the target(s), or remove the broken SRV record.",
+ strings.Join(resolveFails, "
"))),
+ })
+ }
+ if len(cnames) > 0 {
+ rd.Alerts = append(rd.Alerts, reportAlert{
+ Severity: "warn",
+ Title: "SRV target is a CNAME (RFC 2782 violation)",
+ Body: template.HTML(fmt.Sprintf(
+ "Target(s): %s
RFC 2782 requires SRV targets to resolve directly to A/AAAA. "+
+ "Some clients will refuse to follow the CNAME. Fix: point the SRV record to a hostname with A/AAAA records, "+
+ "or replace the CNAME with an ALIAS/ANAME at the DNS provider.",
+ ""+strings.Join(cnames, ", ")+"")),
+ })
+ }
+ if len(tcpDown) > 0 {
+ var items []string
+ for _, f := range tcpDown {
+ items = append(items, fmt.Sprintf("%s (%s): %s",
+ template.HTMLEscapeString(f.address),
+ template.HTMLEscapeString(f.owner),
+ template.HTMLEscapeString(f.err)))
+ }
+ 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, "
") +
+ "
Check: (1) the server is running and bound to the right port; " +
+ "(2) firewall/security-group allows inbound TCP to that port; " +
+ "(3) the SRV record is not pointing at an old IP."),
+ })
+ }
+ if len(nulls) > 0 && len(nulls) == len(d.Records) {
+ rd.Alerts = append(rd.Alerts, reportAlert{
+ Severity: "warn",
+ Title: "All SRV records use the null target (\".\"): service is explicitly disabled",
+ Body: template.HTML(
+ "RFC 2782 defines a single SRV record with target \".\" 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."),
+ })
}
- 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, "
") +
- "
Check: (1) the server is running and bound to the right port; " +
- "(2) firewall/security-group allows inbound TCP to that port; " +
- "(3) the SRV record is not pointing at an old IP."),
- })
- }
- if len(nulls) > 0 && len(nulls) == len(d.Records) {
- rd.Alerts = append(rd.Alerts, reportAlert{
- Severity: "warn",
- Title: "All SRV records use the null target (\".\"): service is explicitly disabled",
- Body: template.HTML(
- "RFC 2782 defines a single SRV record with target \".\" 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