begins work on routing lib

This commit is contained in:
Owen Diehl
2021-02-24 17:06:55 -05:00
parent 0ef573754f
commit 4ba7757281
3 changed files with 48 additions and 220 deletions
+48
View File
@@ -0,0 +1,48 @@
package routing
import (
"github.com/grafana/alerting-api/pkg/api"
"github.com/prometheus/alertmanager/config"
)
// GrafanaAlertingConfig contains only the Grafana managed alerting configurations.
type GrafanaAlertingConfig struct {
Route *config.Route `yaml:"route,omitempty" json:"route,omitempty"`
Templates []string `yaml:"templates" json:"templates"`
Receivers []*GrafanaReceiver `yaml:"receivers,omitempty" json:"receivers,omitempty"`
}
type GrafanaReceiver struct {
// A unique identifier for this receiver.
Name string `yaml:"name" json:"name"`
api.GrafanaReceivers
}
func SplitAlertingConfig(apiConf api.ApiAlertingConfig) (amConfig config.Config, gConfig GrafanaAlertingConfig, err error) {
var gReceivers []*GrafanaReceiver
var amReceivers []*config.Receiver
for _, r := range apiConf.Receivers {
t := r.Type()
if t == api.GrafanaReceiverType {
gReceivers = append(gReceivers, &GrafanaReceiver{
Name: r.Name,
GrafanaReceivers: r.GrafanaReceivers,
})
} else {
amReceivers = append(amReceivers, &r.Receiver)
}
}
// Create Grafana specific config
gConfig.Templates = apiConf.Templates
gConfig.Route = apiConf.GrafanaManagedRoute
gConfig.Receivers = gReceivers
// Create AM specific config
amConfig = apiConf.Config
amConfig.Route = apiConf.AlertManagerRoute
amConfig.Receivers = amReceivers
return amConfig, gConfig, nil
}
-64
View File
@@ -1,64 +0,0 @@
package validation
import (
"fmt"
"github.com/grafana/alerting-api/pkg/api"
"github.com/prometheus/alertmanager/config"
)
// GrafanaAlertingConfig contains only the Grafana managed alerting configurations.
type GrafanaAlertingConfig struct {
api.GrafanaReceivers
Route *config.Route `yaml:"route,omitempty" json:"route,omitempty"`
Templates []string `yaml:"templates" json:"templates"`
}
// func SplitAlertingConfig(apiConf api.ApiAlertingConfig) (amConfig config.Config, gConfig GrafanaAlertingConfig, err error) {
// }
// func MergeAlertingConfigs(amConfig config.Config, gConfig GrafanaAlertingConfig) (conf api.ApiAlertingConfig, err error) {
// }
// Routing trees must either contain only Grafana Managed receiver types or AlertManager receiver types
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)
for _, subRoute := range route.Routes {
res = append(res, allReceivers(subRoute)...)
}
return res
}
-156
View File
@@ -1,156 +0,0 @@
package validation
import (
"testing"
"github.com/grafana/alerting-api/pkg/api"
"github.com/prometheus/alertmanager/config"
"github.com/stretchr/testify/require"
)
func Test_allReceivers(t *testing.T) {
input := &config.Route{
Receiver: "foo",
Routes: []*config.Route{
{
Receiver: "bar",
Routes: []*config.Route{
{
Receiver: "bazz",
},
},
},
{
Receiver: "buzz",
},
},
}
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)
}
})
}
}