[Alerting] Route validations (#34393)

* more routing validation

* go mod

* recursive route validations
This commit is contained in:
Owen Diehl 2021-05-19 10:36:28 -04:00 committed by GitHub
parent 958ebce1e1
commit 1d2febfa85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 117 additions and 5 deletions

2
go.mod
View File

@ -14,7 +14,7 @@ replace k8s.io/client-go => k8s.io/client-go v0.18.8
require (
cloud.google.com/go/storage v1.14.0
cuelang.org/go v0.3.2
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.16.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.16.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.8.0
github.com/BurntSushi/toml v0.3.1
github.com/Masterminds/semver v1.5.0

View File

@ -6,6 +6,7 @@ import (
"fmt"
"reflect"
"github.com/pkg/errors"
amv2 "github.com/prometheus/alertmanager/api/v2/models"
"github.com/prometheus/alertmanager/config"
"gopkg.in/yaml.v3"
@ -484,10 +485,26 @@ func (c *Config) UnmarshalJSON(b []byte) error {
}
}
if c.Route != nil {
if err := c.Route.UnmarshalYAML(noopUnmarshal); err != nil {
return err
}
if c.Route == nil {
return fmt.Errorf("no routes provided")
}
// Route is a recursive structure that includes validation in the yaml unmarshaler.
// Therefore, we'll redirect json -> yaml to utilize these.
b, err := yaml.Marshal(c.Route)
if err != nil {
return errors.Wrap(err, "marshaling route to yaml for validation")
}
err = yaml.Unmarshal(b, c.Route)
if err != nil {
return errors.Wrap(err, "unmarshaling route for validations")
}
if len(c.Route.Receiver) == 0 {
return fmt.Errorf("root route must specify a default receiver")
}
if len(c.Route.Match) > 0 || len(c.Route.MatchRE) > 0 {
return fmt.Errorf("root route must not have any matchers")
}
for _, r := range c.InhibitRules {

View File

@ -243,6 +243,101 @@ func Test_ApiAlertingConfig_Marshaling(t *testing.T) {
},
err: true,
},
{
desc: "failure graf no route",
input: PostableApiAlertingConfig{
Receivers: []*PostableApiReceiver{
{
Receiver: config.Receiver{
Name: "graf",
},
PostableGrafanaReceivers: PostableGrafanaReceivers{
GrafanaManagedReceivers: []*PostableGrafanaReceiver{{}},
},
},
},
},
err: true,
},
{
desc: "failure graf no default receiver",
input: PostableApiAlertingConfig{
Config: Config{
Route: &config.Route{
Routes: []*config.Route{
{
Receiver: "graf",
},
},
},
},
Receivers: []*PostableApiReceiver{
{
Receiver: config.Receiver{
Name: "graf",
},
PostableGrafanaReceivers: PostableGrafanaReceivers{
GrafanaManagedReceivers: []*PostableGrafanaReceiver{{}},
},
},
},
},
err: true,
},
{
desc: "failure graf root route with matchers",
input: PostableApiAlertingConfig{
Config: Config{
Route: &config.Route{
Receiver: "graf",
Routes: []*config.Route{
{
Receiver: "graf",
},
},
Match: map[string]string{"foo": "bar"},
},
},
Receivers: []*PostableApiReceiver{
{
Receiver: config.Receiver{
Name: "graf",
},
PostableGrafanaReceivers: PostableGrafanaReceivers{
GrafanaManagedReceivers: []*PostableGrafanaReceiver{{}},
},
},
},
},
err: true,
},
{
desc: "failure graf nested route duplicate group by labels",
input: PostableApiAlertingConfig{
Config: Config{
Route: &config.Route{
Receiver: "graf",
Routes: []*config.Route{
{
Receiver: "graf",
GroupByStr: []string{"foo", "bar", "foo"},
},
},
},
},
Receivers: []*PostableApiReceiver{
{
Receiver: config.Receiver{
Name: "graf",
},
PostableGrafanaReceivers: PostableGrafanaReceivers{
GrafanaManagedReceivers: []*PostableGrafanaReceiver{{}},
},
},
},
},
err: true,
},
} {
t.Run(tc.desc, func(t *testing.T) {
encoded, err := json.Marshal(tc.input)