Merge pull request #17 from grafana/single-routing-tree

Single routing tree
This commit is contained in:
Owen Diehl
2021-02-26 11:32:09 -05:00
committed by GitHub
6 changed files with 60 additions and 218 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ GO_PKG_FILES = $(shell find $(PKG_DIR) -name *.go -print)
spec.json: $(GO_PKG_FILES)
swagger generate spec -m -w $(PKG_DIR) | jq 'del(.definitions.ApiAlertingConfig.properties.route)' > $@
swagger generate spec -m -w $(PKG_DIR) -o $@
.PHONY: openapi
-1
View File
@@ -11,4 +11,3 @@ This repo aims to define the unified alerting API as code. It generates OpenAPI
## Requires
- [go-swagger](https://github.com/go-swagger/go-swagger)
- [jq](https://stedolan.github.io/jq/)
+15 -25
View File
@@ -180,12 +180,6 @@ type AlertingConfigResponse struct {
type ApiAlertingConfig struct {
config.Config
// TODO: PR a followup to https://github.com/go-swagger/go-swagger/pull/1527 in order to allow
// explicitly ignoring embedded fields. In the meantime, these are hackily removed in our make targets via `jq`
AlertManagerRoute *config.Route `yaml:"alertmanager_route,omitempty" json:"alertmanager_route,omitempty"`
GrafanaManagedRoute *config.Route `yaml:"grafana_managed_route,omitempty" json:"grafana_managed_route,omitempty"`
// Override with our superset receiver type
Receivers []*ApiReceiver `yaml:"receivers,omitempty" json:"receivers,omitempty"`
}
@@ -201,32 +195,28 @@ func (c *ApiAlertingConfig) UnmarshalJSON(b []byte) error {
// validate ensures that the two routing trees use the correct receiver types.
func (c *ApiAlertingConfig) validate() error {
receivers := make(map[string]ReceiverType, len(c.Receivers))
receivers := make(map[string]struct{}, len(c.Receivers))
var hasGrafReceivers, hasAMReceivers bool
for _, r := range c.Receivers {
receivers[r.Name] = r.Type()
receivers[r.Name] = struct{}{}
switch r.Type() {
case GrafanaReceiverType:
hasGrafReceivers = true
case AlertmanagerReceiverType:
hasAMReceivers = true
}
}
for _, receiver := range AllReceivers(c.GrafanaManagedRoute) {
t, ok := receivers[receiver]
if hasGrafReceivers && hasAMReceivers {
return fmt.Errorf("cannot mix Alertmanager & Grafana receiver types")
}
for _, receiver := range AllReceivers(c.Route) {
_, ok := receivers[receiver]
if !ok {
return fmt.Errorf("unexpected receiver (%s) is undefined", receiver)
}
if t != GrafanaReceiverType {
return fmt.Errorf("unexpected receiver (%s): cannot use Alertmanager receiver types in Grafana managed routes", receiver)
}
}
for _, receiver := range AllReceivers(c.AlertManagerRoute) {
t, ok := receivers[receiver]
if !ok {
return fmt.Errorf("unexpected receiver (%s) is undefined", receiver)
}
if t != AlertmanagerReceiverType {
return fmt.Errorf("unexpected receiver (%s): cannot use Grafana receiver types in non-Grafana managed routes", receiver)
}
}
return nil
+39 -135
View File
@@ -92,22 +92,15 @@ func Test_ApiAlertingConfig_Marshaling(t *testing.T) {
err bool
}{
{
desc: "success",
desc: "success am",
input: ApiAlertingConfig{
Config: config.Config{},
AlertManagerRoute: &config.Route{
Receiver: "am",
Routes: []*config.Route{
{
Receiver: "am",
},
},
},
GrafanaManagedRoute: &config.Route{
Receiver: "graf",
Routes: []*config.Route{
{
Receiver: "graf",
Config: config.Config{
Route: &config.Route{
Receiver: "am",
Routes: []*config.Route{
{
Receiver: "am",
},
},
},
},
@@ -118,6 +111,23 @@ func Test_ApiAlertingConfig_Marshaling(t *testing.T) {
EmailConfigs: []*config.EmailConfig{{}},
},
},
},
},
},
{
desc: "success graf",
input: ApiAlertingConfig{
Config: config.Config{
Route: &config.Route{
Receiver: "graf",
Routes: []*config.Route{
{
Receiver: "graf",
},
},
},
},
Receivers: []*ApiReceiver{
{
Receiver: config.Receiver{
Name: "graf",
@@ -132,20 +142,13 @@ func Test_ApiAlertingConfig_Marshaling(t *testing.T) {
{
desc: "failure undefined am receiver",
input: ApiAlertingConfig{
Config: config.Config{},
AlertManagerRoute: &config.Route{
Receiver: "am",
Routes: []*config.Route{
{
Receiver: "unmentioned",
},
},
},
GrafanaManagedRoute: &config.Route{
Receiver: "graf",
Routes: []*config.Route{
{
Receiver: "graf",
Config: config.Config{
Route: &config.Route{
Receiver: "am",
Routes: []*config.Route{
{
Receiver: "unmentioned",
},
},
},
},
@@ -156,14 +159,6 @@ func Test_ApiAlertingConfig_Marshaling(t *testing.T) {
EmailConfigs: []*config.EmailConfig{{}},
},
},
{
Receiver: config.Receiver{
Name: "graf",
},
GrafanaReceivers: GrafanaReceivers{
GrafanaManagedReceivers: []*GrafanaReceiver{{}},
},
},
},
},
err: true,
@@ -171,108 +166,17 @@ func Test_ApiAlertingConfig_Marshaling(t *testing.T) {
{
desc: "failure undefined graf receiver",
input: ApiAlertingConfig{
Config: config.Config{},
AlertManagerRoute: &config.Route{
Receiver: "am",
Routes: []*config.Route{
{
Receiver: "am",
},
},
},
GrafanaManagedRoute: &config.Route{
Receiver: "graf",
Routes: []*config.Route{
{
Receiver: "unmentioned",
Config: config.Config{
Route: &config.Route{
Receiver: "graf",
Routes: []*config.Route{
{
Receiver: "unmentioned",
},
},
},
},
Receivers: []*ApiReceiver{
{
Receiver: config.Receiver{
Name: "am",
EmailConfigs: []*config.EmailConfig{{}},
},
},
{
Receiver: config.Receiver{
Name: "graf",
},
GrafanaReceivers: GrafanaReceivers{
GrafanaManagedReceivers: []*GrafanaReceiver{{}},
},
},
},
},
err: true,
},
{
desc: "failure mixed AM in Grafana",
input: ApiAlertingConfig{
Config: config.Config{},
AlertManagerRoute: &config.Route{
Receiver: "am",
Routes: []*config.Route{
{
Receiver: "am",
},
},
},
GrafanaManagedRoute: &config.Route{
Receiver: "graf",
Routes: []*config.Route{
{
Receiver: "am",
},
},
},
Receivers: []*ApiReceiver{
{
Receiver: config.Receiver{
Name: "am",
EmailConfigs: []*config.EmailConfig{{}},
},
},
{
Receiver: config.Receiver{
Name: "graf",
},
GrafanaReceivers: GrafanaReceivers{
GrafanaManagedReceivers: []*GrafanaReceiver{{}},
},
},
},
},
err: true,
},
{
desc: "failure mixed Grafana in AM",
input: ApiAlertingConfig{
Config: config.Config{},
AlertManagerRoute: &config.Route{
Receiver: "am",
Routes: []*config.Route{
{
Receiver: "graf",
},
},
},
GrafanaManagedRoute: &config.Route{
Receiver: "graf",
Routes: []*config.Route{
{
Receiver: "graf",
},
},
},
Receivers: []*ApiReceiver{
{
Receiver: config.Receiver{
Name: "am",
EmailConfigs: []*config.EmailConfig{{}},
},
},
{
Receiver: config.Receiver{
Name: "graf",
-48
View File
@@ -1,48 +0,0 @@
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
}
+5 -8
View File
@@ -1021,15 +1021,9 @@
"ApiAlertingConfig": {
"type": "object",
"properties": {
"alertmanager_route": {
"$ref": "#/definitions/Route"
},
"global": {
"$ref": "#/definitions/GlobalConfig"
},
"grafana_managed_route": {
"$ref": "#/definitions/Route"
},
"inhibit_rules": {
"type": "array",
"items": {
@@ -1045,6 +1039,9 @@
},
"x-go-name": "Receivers"
},
"route": {
"$ref": "#/definitions/Route"
},
"templates": {
"type": "array",
"items": {
@@ -1736,7 +1733,7 @@
"properties": {
"Expr": {
"type": "string",
"example": "(node_filesystem_avail_bytes{fstype!=\"\",job=\"integrations/node_exporter\"} node_filesystem_size_bytes{fstype!=\"\",job=\"integrations/node_exporter\"} * 100 < 5 and node_filesystem_readonly{fstype!=\"\",job=\"integrations/node_exporter\"} == 0)"
"example": "(node_filesystem_avail_bytes{fstype!=\"\",job=\"integrations/node_exporter\"} node_filesystem_size_bytes{fstype!=\"\",job=\"integrations/node_exporter\"} * 100 \u003c 5 and node_filesystem_readonly{fstype!=\"\",job=\"integrations/node_exporter\"} == 0)"
},
"datasourceUid": {
"description": "DatasourceUID is required if the query will be sent to grafana to be executed",
@@ -3561,4 +3558,4 @@
"type": "basic"
}
}
}
}