ability to split routes between AM & Grafana

This commit is contained in:
Owen Diehl
2021-02-24 11:15:39 -05:00
parent 3b8ceda26a
commit ded0d4a969
3 changed files with 170 additions and 7 deletions
+9 -3
View File
@@ -183,8 +183,8 @@ type GrafanaReceiver models.CreateAlertNotificationCommand
type ReceiverType int
const (
GrafanaManagedReceiver ReceiverType = iota
AMReceiver
GrafanaReceiverType ReceiverType = iota
AlertmanagerReceiverType
)
type ApiReceiver struct {
@@ -227,11 +227,17 @@ func (r *ApiReceiver) UnmarshalJSON(b []byte) error {
}
}
return nil
}
func (r *ApiReceiver) Type() ReceiverType {
if len(r.GrafanaReceivers.GrafanaManagedReceivers) > 0 {
return GrafanaReceiverType
}
return AlertmanagerReceiverType
}
type GrafanaReceivers struct {
GrafanaManagedReceivers []*GrafanaReceiver `yaml:"grafana_managed_receiver_configs,omitempty" json:"grafana_managed_receiver_configs,omitempty"`
}
+34 -4
View File
@@ -1,6 +1,8 @@
package validation
import (
"fmt"
"github.com/grafana/alerting-api/pkg/api"
"github.com/prometheus/alertmanager/config"
)
@@ -20,10 +22,38 @@ type GrafanaAlertingConfig struct {
// }
// Routing trees must either contain only Grafana Managed receiver types or AlertManager receiver types
// func SplitRoutes(routes []*config.Route, receivers map[string]*api.ApiReceiver) (gRoutes, amRoutes []*config.Route, err error) {
// for _, route := range routes {
// }
// }
func SplitRoutes(routes []*config.Route, receivers map[string]api.ReceiverType) (gRoutes, amRoutes []*config.Route, err error) {
for _, route := range routes {
var grafanaCt, amCt int
for _, receiver := range allReceivers(route) {
t, ok := receivers[receiver]
if !ok {
return nil, nil, fmt.Errorf("unexpected receiver (%s) is undefined", receiver)
}
if t == api.GrafanaReceiverType {
grafanaCt++
} else {
amCt++
}
}
// TODO(owen-d): We may want to eventually support this, but short-circuiting for now
// to reduce routing tree complexity.
if grafanaCt > 0 && amCt > 0 {
return nil, nil, fmt.Errorf("cannot mix Grafana Managed receivers with Alertmanager receivers in the same (non-root) routing tree")
}
if grafanaCt > 0 {
gRoutes = append(gRoutes, route)
} else {
amRoutes = append(amRoutes, route)
}
}
return gRoutes, amRoutes, nil
}
func allReceivers(route *config.Route) (res []string) {
res = append(res, route.Receiver)
+127
View File
@@ -3,6 +3,7 @@ package validation
import (
"testing"
"github.com/grafana/alerting-api/pkg/api"
"github.com/prometheus/alertmanager/config"
"github.com/stretchr/testify/require"
)
@@ -27,3 +28,129 @@ func Test_allReceivers(t *testing.T) {
require.Equal(t, []string{"foo", "bar", "bazz", "buzz"}, allReceivers(input))
}
func Test_Splitroutes(t *testing.T) {
receivers := map[string]api.ReceiverType{
"am": api.AlertmanagerReceiverType,
"graf": api.GrafanaReceiverType,
}
for _, tc := range []struct {
desc string
input []*config.Route
receivers map[string]api.ReceiverType
err bool
gRoutes, amRoutes []*config.Route
}{
{
desc: "splits simple",
input: []*config.Route{
{
Receiver: "am",
},
{
Receiver: "graf",
},
},
err: false,
gRoutes: []*config.Route{
{
Receiver: "graf",
},
},
amRoutes: []*config.Route{
{
Receiver: "am",
},
},
},
{
desc: "splits nested",
input: []*config.Route{
{
Receiver: "am",
Routes: []*config.Route{
{
Receiver: "am",
},
},
},
{
Receiver: "graf",
Routes: []*config.Route{
{
Receiver: "graf",
},
},
},
},
err: false,
gRoutes: []*config.Route{
{
Receiver: "graf",
Routes: []*config.Route{
{
Receiver: "graf",
},
},
},
},
amRoutes: []*config.Route{
{
Receiver: "am",
Routes: []*config.Route{
{
Receiver: "am",
},
},
},
},
},
{
desc: "errors undefined receiver",
input: []*config.Route{
{
Receiver: "am",
Routes: []*config.Route{
{
Receiver: "unmentioned",
},
},
},
},
err: true,
},
{
desc: "errors mixed",
input: []*config.Route{
{
Receiver: "am",
Routes: []*config.Route{
{
Receiver: "graf",
},
},
},
{
Receiver: "graf",
Routes: []*config.Route{
{
Receiver: "graf",
},
},
},
},
err: true,
},
} {
t.Run(tc.desc, func(t *testing.T) {
gRoutes, amRoutes, err := SplitRoutes(tc.input, receivers)
if tc.err {
require.Error(t, err)
} else {
require.Equal(t, tc.gRoutes, gRoutes)
require.Equal(t, tc.amRoutes, amRoutes)
}
})
}
}