Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alertmanager: Add Grafana's external URL #8498

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/alertmanager/alertmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ type Config struct {
PersisterConfig PersisterConfig

GrafanaAlertmanagerCompatibility bool
GrafanaExternalURL string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to store it - it will only get used in ApplyConfig.

}

// An Alertmanager manages the alerts for one user.
Expand Down
111 changes: 83 additions & 28 deletions pkg/alertmanager/alertspb/alerts.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pkg/alertmanager/alertspb/alerts.proto
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ message GrafanaAlertConfigDesc {
int64 created_at_timestamp = 5;
bool default = 7;
bool promoted = 8;
string external_url = 9;
}
3 changes: 2 additions & 1 deletion pkg/alertmanager/alertspb/compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ func ToProto(cfg string, templates map[string]string, user string) AlertConfigDe
}

// ToGrafanaProto transforms a Grafana Alertmanager config to a GrafanaAlertConfigDesc.
func ToGrafanaProto(cfg, user, hash string, createdAtTimestamp int64, isDefault, isPromoted bool) GrafanaAlertConfigDesc {
func ToGrafanaProto(cfg, user, hash string, createdAtTimestamp int64, isDefault, isPromoted bool, externalURL string) GrafanaAlertConfigDesc {
return GrafanaAlertConfigDesc{
User: user,
RawConfig: cfg,
Hash: hash,
CreatedAtTimestamp: createdAtTimestamp,
Default: isDefault,
Promoted: isPromoted,
ExternalUrl: externalURL,
}
}

Expand Down
5 changes: 4 additions & 1 deletion pkg/alertmanager/api_grafana.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type UserGrafanaConfig struct {
CreatedAt int64 `json:"created"`
Default bool `json:"default"`
Promoted bool `json:"promoted"`
ExternalURL string `json:"external_url"`
}

func (gc *UserGrafanaConfig) Validate() error {
Expand Down Expand Up @@ -290,6 +291,8 @@ func (am *MultitenantAlertmanager) GetUserGrafanaConfig(w http.ResponseWriter, r
Hash: cfg.Hash,
CreatedAt: cfg.CreatedAtTimestamp,
Default: cfg.Default,
Promoted: cfg.Promoted,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick fix, we forgot to add this field in the response to GET api/v1/grafana/config

ExternalURL: cfg.ExternalUrl,
},
})
}
Expand Down Expand Up @@ -329,7 +332,7 @@ func (am *MultitenantAlertmanager) SetUserGrafanaConfig(w http.ResponseWriter, r
return
}

cfgDesc := alertspb.ToGrafanaProto(string(rawCfg), userID, cfg.Hash, cfg.CreatedAt, cfg.Default, cfg.Promoted)
cfgDesc := alertspb.ToGrafanaProto(string(rawCfg), userID, cfg.Hash, cfg.CreatedAt, cfg.Default, cfg.Promoted, cfg.ExternalURL)
err = am.store.SetGrafanaAlertConfig(r.Context(), cfgDesc)
if err != nil {
level.Error(logger).Log("msg", errStoringGrafanaConfig, "err", err.Error())
Expand Down
10 changes: 7 additions & 3 deletions pkg/alertmanager/api_grafana_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,14 @@ func TestMultitenantAlertmanager_GetUserGrafanaConfig(t *testing.T) {
logger: test.NewTestingLogger(t),
}

externalURL := "http://test.grafana.com"
require.NoError(t, alertstore.SetGrafanaAlertConfig(context.Background(), alertspb.GrafanaAlertConfigDesc{
User: "test_user",
RawConfig: testGrafanaConfig,
Hash: "bb788eaa294c05ec556c1ed87546b7a9",
CreatedAtTimestamp: now,
Default: false,
ExternalUrl: externalURL,
}))

require.Len(t, storage.Objects(), 1)
Expand Down Expand Up @@ -231,11 +233,12 @@ func TestMultitenantAlertmanager_GetUserGrafanaConfig(t *testing.T) {
"configuration_hash": "bb788eaa294c05ec556c1ed87546b7a9",
"created": %d,
"default": false,
"promoted": false
"promoted": false,
"external_url": %q
},
"status": "success"
}
`, testGrafanaConfig, now)
`, testGrafanaConfig, now, externalURL)

require.JSONEq(t, json, string(body))
require.Equal(t, "application/json", rec.Header().Get("Content-Type"))
Expand Down Expand Up @@ -347,7 +350,8 @@ func TestMultitenantAlertmanager_SetUserGrafanaConfig(t *testing.T) {
"configuration_hash": "ChEKBW5mbG9nEghzb21lZGF0YQ==",
"created": 12312414343,
"default": false,
"promoted": true
"promoted": true,
"external_url": "http://test.grafana.com"
}
`, testGrafanaConfig)
req.Body = io.NopCloser(strings.NewReader(json))
Expand Down
12 changes: 7 additions & 5 deletions pkg/alertmanager/multitenant.go
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ func (am *MultitenantAlertmanager) syncConfigs(cfgMap map[string]alertspb.AlertC
continue
}

if err := am.setConfig(cfg); err != nil {
if err := am.setConfig(cfg, cfgs.Grafana.ExternalUrl); err != nil {
am.multitenantMetrics.lastReloadSuccessful.WithLabelValues(user).Set(float64(0))
level.Warn(am.logger).Log("msg", "error applying config", "err", err)
continue
Expand Down Expand Up @@ -717,7 +717,7 @@ func (am *MultitenantAlertmanager) computeConfig(cfgs alertspb.AlertConfigDescs)

// setConfig applies the given configuration to the alertmanager for `userID`,
// creating an alertmanager if it doesn't already exist.
func (am *MultitenantAlertmanager) setConfig(cfg alertspb.AlertConfigDesc) error {
func (am *MultitenantAlertmanager) setConfig(cfg alertspb.AlertConfigDesc, grafanaURL string) error {
var userAmConfig *definition.PostableApiAlertingConfig
var err error
var hasTemplateChanges bool
Expand Down Expand Up @@ -806,7 +806,7 @@ func (am *MultitenantAlertmanager) setConfig(cfg alertspb.AlertConfigDesc) error
// If no Alertmanager instance exists for this user yet, start one.
if !hasExisting {
level.Debug(am.logger).Log("msg", "initializing new per-tenant alertmanager", "user", cfg.User)
newAM, err := am.newAlertmanager(cfg.User, userAmConfig, rawCfg)
newAM, err := am.newAlertmanager(cfg.User, userAmConfig, rawCfg, grafanaURL)
if err != nil {
return err
}
Expand All @@ -828,7 +828,7 @@ func (am *MultitenantAlertmanager) getTenantDirectory(userID string) string {
return filepath.Join(am.cfg.DataDir, userID)
}

func (am *MultitenantAlertmanager) newAlertmanager(userID string, amConfig *definition.PostableApiAlertingConfig, rawCfg string) (*Alertmanager, error) {
func (am *MultitenantAlertmanager) newAlertmanager(userID string, amConfig *definition.PostableApiAlertingConfig, rawCfg string, grafanaURL string) (*Alertmanager, error) {
reg := prometheus.NewRegistry()

tenantDir := am.getTenantDirectory(userID)
Expand All @@ -852,6 +852,7 @@ func (am *MultitenantAlertmanager) newAlertmanager(userID string, amConfig *defi
Limits: am.limits,
Features: am.features,
GrafanaAlertmanagerCompatibility: am.cfg.GrafanaAlertmanagerCompatibilityEnabled,
GrafanaExternalURL: grafanaURL,
}, reg)
if err != nil {
return nil, fmt.Errorf("unable to start Alertmanager for user %v: %v", userID, err)
Expand Down Expand Up @@ -973,7 +974,8 @@ func (am *MultitenantAlertmanager) alertmanagerFromFallbackConfig(ctx context.Co
}

// Calling setConfig with an empty configuration will use the fallback config.
err = am.setConfig(cfgDesc)
// We're not using Grafana Alertmanager configuration, so we pass an empty Grafana URL.
err = am.setConfig(cfgDesc, "")
if err != nil {
return nil, err
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/alertmanager/multitenant_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ templates:
CreatedAtTimestamp: time.Now().Unix(),
Default: false,
Promoted: true,
ExternalUrl: "test.grafana.com",
}
emptyMimirConfig := alertspb.AlertConfigDesc{User: "user4"}
require.NoError(t, store.SetGrafanaAlertConfig(ctx, userGrafanaCfg))
Expand All @@ -379,6 +380,9 @@ templates:
require.NotZero(t, user4Dir)
require.True(t, dirExists(t, user4Dir))

// Check that the external URL for Grafana was correctly set.
require.Equal(t, userGrafanaCfg.ExternalUrl, am.alertmanagers["user4"].cfg.GrafanaExternalURL)

require.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(`
# HELP cortex_alertmanager_config_last_reload_successful Boolean set to 1 whenever the last configuration reload attempt was successful.
# TYPE cortex_alertmanager_config_last_reload_successful gauge
Expand Down
Loading