From 4ba7757281720d7b09ca83c8cf60a76e9ec937b7 Mon Sep 17 00:00:00 2001 From: Owen Diehl Date: Wed, 24 Feb 2021 17:06:55 -0500 Subject: [PATCH] begins work on routing lib --- pkg/routing/alertconfig.go | 48 +++++++++ pkg/validation/alertconfig.go | 64 ------------ pkg/validation/alertconfig_test.go | 156 ----------------------------- 3 files changed, 48 insertions(+), 220 deletions(-) create mode 100644 pkg/routing/alertconfig.go delete mode 100644 pkg/validation/alertconfig.go delete mode 100644 pkg/validation/alertconfig_test.go diff --git a/pkg/routing/alertconfig.go b/pkg/routing/alertconfig.go new file mode 100644 index 00000000000..45f486efffe --- /dev/null +++ b/pkg/routing/alertconfig.go @@ -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 +} diff --git a/pkg/validation/alertconfig.go b/pkg/validation/alertconfig.go deleted file mode 100644 index 1b73a722f40..00000000000 --- a/pkg/validation/alertconfig.go +++ /dev/null @@ -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 -} diff --git a/pkg/validation/alertconfig_test.go b/pkg/validation/alertconfig_test.go deleted file mode 100644 index 29f2d099e3c..00000000000 --- a/pkg/validation/alertconfig_test.go +++ /dev/null @@ -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) - } - }) - } -}