checker: add domain length validation and refactor rules into per-concern checks
This commit is contained in:
parent
df0d429150
commit
946ec446d2
15 changed files with 716 additions and 308 deletions
|
|
@ -9,21 +9,9 @@ import (
|
|||
sdk "git.happydns.org/checker-sdk-go/checker"
|
||||
)
|
||||
|
||||
func Rule() sdk.CheckRule {
|
||||
return &xmppRule{}
|
||||
}
|
||||
|
||||
type xmppRule struct{}
|
||||
|
||||
func (r *xmppRule) Name() string {
|
||||
return "xmpp_server"
|
||||
}
|
||||
|
||||
func (r *xmppRule) Description() string {
|
||||
return "Checks discovery, STARTTLS, SASL and federation auth of an XMPP server"
|
||||
}
|
||||
|
||||
func (r *xmppRule) ValidateOptions(opts sdk.CheckerOptions) error {
|
||||
// validateXMPPOptions is the shared options validator for both the provider
|
||||
// and the aggregate rule.
|
||||
func validateXMPPOptions(opts sdk.CheckerOptions) error {
|
||||
if v, ok := opts["mode"]; ok {
|
||||
if s, ok := v.(string); ok && s != "" && !slices.Contains(validModes, s) {
|
||||
return fmt.Errorf(`mode must be "c2s", "s2s", or "both"`)
|
||||
|
|
@ -32,29 +20,41 @@ func (r *xmppRule) ValidateOptions(opts sdk.CheckerOptions) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ValidateOptions implements sdk.OptionsValidator on the provider.
|
||||
func (p *xmppProvider) ValidateOptions(opts sdk.CheckerOptions) error {
|
||||
return validateXMPPOptions(opts)
|
||||
}
|
||||
|
||||
// xmppRule is a minimal back-compat aggregate rule. Newer deployments should
|
||||
// prefer the split per-concern rules exposed by Rules(); this one is kept so
|
||||
// existing tests that compose a single-status output keep working.
|
||||
type xmppRule struct{}
|
||||
|
||||
func (r *xmppRule) Name() string { return "xmpp_server" }
|
||||
func (r *xmppRule) Description() string {
|
||||
return "Aggregate XMPP posture (prefer the per-concern rules)."
|
||||
}
|
||||
|
||||
func (r *xmppRule) ValidateOptions(opts sdk.CheckerOptions) error {
|
||||
return validateXMPPOptions(opts)
|
||||
}
|
||||
|
||||
func (r *xmppRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState {
|
||||
var data XMPPData
|
||||
if err := obs.Get(ctx, ObservationKeyXMPP, &data); err != nil {
|
||||
return []sdk.CheckState{{
|
||||
Status: sdk.StatusError,
|
||||
Message: fmt.Sprintf("failed to load XMPP observation: %v", err),
|
||||
Code: "xmpp.observation_error",
|
||||
}}
|
||||
data, errSt := loadXMPPData(ctx, obs)
|
||||
if errSt != nil {
|
||||
return []sdk.CheckState{*errSt}
|
||||
}
|
||||
wantC2S, wantS2S := wantsFromOpts(opts)
|
||||
issues := deriveIssues(data, wantC2S, wantS2S)
|
||||
|
||||
issues := append([]Issue(nil), data.Issues...)
|
||||
|
||||
// Fold related TLS observations (from a downstream TLS checker, if any)
|
||||
// into the XMPP issue list so cert/chain problems show up on the XMPP
|
||||
// service page without requiring a separate glance at the TLS checker.
|
||||
// Fold related TLS observations into the aggregate so cert/chain
|
||||
// problems surface on the XMPP service page.
|
||||
related, _ := obs.GetRelated(ctx, TLSRelatedKey)
|
||||
issues = append(issues, tlsIssuesFromRelated(related)...)
|
||||
|
||||
// Reduce issue list to the worst severity.
|
||||
worst := sdk.StatusOK
|
||||
critMsgs, warnMsgs := []string{}, []string{}
|
||||
var critMsgs, warnMsgs []string
|
||||
var firstCritCode, firstWarnCode string
|
||||
|
||||
for _, is := range issues {
|
||||
switch is.Severity {
|
||||
case SeverityCrit:
|
||||
|
|
@ -76,15 +76,6 @@ func (r *xmppRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts
|
|||
}
|
||||
}
|
||||
|
||||
mode, _ := sdk.GetOption[string](opts, "mode")
|
||||
if mode == "" {
|
||||
mode = "both"
|
||||
}
|
||||
wantC2S := mode != "s2s"
|
||||
wantS2S := mode != "c2s"
|
||||
|
||||
// Even without issues, the check isn't OK unless we got at least one
|
||||
// working endpoint in each requested mode.
|
||||
if (wantC2S && !data.Coverage.WorkingC2S) || (wantS2S && !data.Coverage.WorkingS2S) {
|
||||
if worst < sdk.StatusCrit {
|
||||
worst = sdk.StatusCrit
|
||||
|
|
@ -96,7 +87,7 @@ func (r *xmppRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts
|
|||
if wantS2S && !data.Coverage.WorkingS2S {
|
||||
missing = append(missing, "s2s")
|
||||
}
|
||||
critMsgs = append(critMsgs, "no working "+strings.Join(missing, "/")+" endpoint")
|
||||
critMsgs = append(critMsgs, "no working "+joinModes(missing)+" endpoint")
|
||||
if firstCritCode == "" {
|
||||
firstCritCode = CodeAllEndpointsDown
|
||||
}
|
||||
|
|
@ -108,7 +99,7 @@ func (r *xmppRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts
|
|||
"has_ipv4": data.Coverage.HasIPv4,
|
||||
"has_ipv6": data.Coverage.HasIPv6,
|
||||
"endpoints": len(data.Endpoints),
|
||||
"issue_count": len(data.Issues),
|
||||
"issue_count": len(issues),
|
||||
}
|
||||
|
||||
switch worst {
|
||||
|
|
@ -136,6 +127,17 @@ func (r *xmppRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts
|
|||
}
|
||||
}
|
||||
|
||||
func joinModes(ms []string) string {
|
||||
switch len(ms) {
|
||||
case 0:
|
||||
return ""
|
||||
case 1:
|
||||
return ms[0]
|
||||
default:
|
||||
return ms[0] + "/" + ms[1]
|
||||
}
|
||||
}
|
||||
|
||||
func joinTop(msgs []string, n int) string {
|
||||
if len(msgs) == 0 {
|
||||
return ""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue