Alerting: Support for Mimir configuration in Grafana Alertmanager (#106402)

This commit is contained in:
Yuri Tseretyan
2025-06-13 16:32:23 +02:00
committed by GitHub
parent 3c0d087186
commit b0ff51a903
6 changed files with 476 additions and 21 deletions
@@ -2,16 +2,22 @@ package notifier
import (
"context"
"net/url"
"testing"
"time"
"github.com/prometheus/alertmanager/config"
"github.com/prometheus/alertmanager/pkg/labels"
"github.com/prometheus/client_golang/prometheus"
promcfg "github.com/prometheus/common/config"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
"github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/ngalert/tests/fakes"
@@ -62,3 +68,145 @@ func TestAlertmanager_newAlertmanager(t *testing.T) {
am := setupAMTest(t)
require.False(t, am.Ready())
}
func TestAlertmanager_ApplyConfig(t *testing.T) {
basicConfig := func() definitions.PostableApiAlertingConfig {
return definitions.PostableApiAlertingConfig{
Config: definitions.Config{
Route: &definitions.Route{
Receiver: "default-receiver",
ObjectMatchers: definitions.ObjectMatchers{
&labels.Matcher{
Type: labels.MatchEqual,
Name: "__grafana_autogenerated__",
Value: "true",
},
},
},
},
Receivers: []*definitions.PostableApiReceiver{
{
Receiver: config.Receiver{
Name: "default-receiver",
},
},
},
}
}
testCases := []struct {
name string
config *definitions.PostableUserConfig
expectedError string
skipInvalid bool
}{
{
name: "basic config",
config: &definitions.PostableUserConfig{
AlertmanagerConfig: basicConfig(),
TemplateFiles: map[string]string{
"grafana-template": "{{ define \"grafana.title\" }}Alert{{ end }}",
},
},
skipInvalid: false,
},
{
name: "with mimir config",
config: &definitions.PostableUserConfig{
AlertmanagerConfig: basicConfig(),
TemplateFiles: map[string]string{
"grafana-template": "{{ define \"grafana.title\" }}Grafana Alert{{ end }}",
},
ExtraConfigs: []definitions.ExtraConfiguration{
{
Identifier: "mimir-prod",
MergeMatchers: config.Matchers{
{
Type: labels.MatchEqual,
Name: "__mimir__",
Value: "true",
},
},
TemplateFiles: map[string]string{
"mimir-template": "{{ define \"mimir.title\" }}Mimir Alert{{ end }}",
},
AlertmanagerConfig: definitions.PostableApiAlertingConfig{
Config: definitions.Config{
Route: &definitions.Route{
Receiver: "mimir-webhook",
GroupBy: []model.LabelName{"alertname", "cluster"},
},
},
Receivers: []*definitions.PostableApiReceiver{
{
Receiver: config.Receiver{
Name: "mimir-webhook",
WebhookConfigs: []*config.WebhookConfig{
{
URL: &config.SecretURL{
URL: &url.URL{
Scheme: "https",
Host: "webhook.example.com",
Path: "/alerts",
},
},
HTTPConfig: &promcfg.DefaultHTTPClientConfig,
},
},
},
},
},
},
},
},
},
skipInvalid: false,
},
{
name: "invalid config fails",
config: &definitions.PostableUserConfig{
AlertmanagerConfig: basicConfig(),
ExtraConfigs: []definitions.ExtraConfiguration{
{
Identifier: "", // invalid: empty identifier
MergeMatchers: config.Matchers{},
AlertmanagerConfig: definitions.PostableApiAlertingConfig{
Config: definitions.Config{
Route: &definitions.Route{
Receiver: "test-receiver",
},
},
},
},
},
},
expectedError: "failed to get full alertmanager configuration",
skipInvalid: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
am := setupAMTest(t)
ctx := context.Background()
changed, err := am.applyConfig(ctx, tc.config, false)
if tc.expectedError != "" {
require.Error(t, err)
require.ErrorContains(t, err, tc.expectedError)
require.False(t, changed)
} else {
require.NoError(t, err)
require.True(t, changed)
templateDefs := tc.config.GetMergedTemplateDefinitions()
expectedTemplateCount := len(tc.config.TemplateFiles)
if len(tc.config.ExtraConfigs) > 0 {
expectedTemplateCount += len(tc.config.ExtraConfigs[0].TemplateFiles)
}
require.Len(t, templateDefs, expectedTemplateCount)
}
})
}
}