Files
grafana/pkg/services/ngalert/api/tooling/definitions/alertmanager_validation.go
Alexander Weaver 60ec10566f Extract Route validation from serialization methods so it can be re-used (#47649)
* Extract validation and reject invalid policies

* Validation in dedicated file

* Tests for validation

* Extract root route validation

* Update call and drop TODO

* empty commit to kick actions

* Normalization should be idempotent

* Cleaner representation of validation errors, chain errors properly

* Make internal validate unexported

* Fix missed rename

* Genericize error message

* Improve method names

* Rebase, fix

* Update asserts
2022-04-27 15:15:41 -05:00

68 lines
1.7 KiB
Go

package definitions
import (
"fmt"
"time"
"github.com/prometheus/common/model"
)
// Validate normalizes a possibly nested Route r, and returns errors if r is invalid.
func (r *Route) validateChild() error {
r.GroupBy = nil
r.GroupByAll = false
for _, l := range r.GroupByStr {
if l == "..." {
r.GroupByAll = true
} else {
r.GroupBy = append(r.GroupBy, model.LabelName(l))
}
}
if len(r.GroupBy) > 0 && r.GroupByAll {
return fmt.Errorf("cannot have wildcard group_by (`...`) and other other labels at the same time")
}
groupBy := map[model.LabelName]struct{}{}
for _, ln := range r.GroupBy {
if _, ok := groupBy[ln]; ok {
return fmt.Errorf("duplicated label %q in group_by, %s %s", ln, r.Receiver, r.GroupBy)
}
groupBy[ln] = struct{}{}
}
if r.GroupInterval != nil && time.Duration(*r.GroupInterval) == time.Duration(0) {
return fmt.Errorf("group_interval cannot be zero")
}
if r.RepeatInterval != nil && time.Duration(*r.RepeatInterval) == time.Duration(0) {
return fmt.Errorf("repeat_interval cannot be zero")
}
// Routes are a self-referential structure.
if r.Routes != nil {
for _, child := range r.Routes {
err := child.validateChild()
if err != nil {
return err
}
}
}
return nil
}
// Validate normalizes a Route r, and returns errors if r is an invalid root route. Root routes must satisfy a few additional conditions.
func (r *Route) Validate() error {
if len(r.Receiver) == 0 {
return fmt.Errorf("root route must specify a default receiver")
}
if len(r.Match) > 0 || len(r.MatchRE) > 0 {
return fmt.Errorf("root route must not have any matchers")
}
if len(r.MuteTimeIntervals) > 0 {
return fmt.Errorf("root route must not have any mute time intervals")
}
return r.validateChild()
}