mirror of https://github.com/grafana/grafana.git
Alerting: Keep extra configurations on main config update (#106958)
This commit is contained in:
parent
843956e795
commit
cd889fef9b
|
@ -324,6 +324,15 @@ func (moa *MultiOrgAlertmanager) SaveAndApplyAlertmanagerConfiguration(ctx conte
|
|||
}
|
||||
cleanPermissionsErr := err
|
||||
|
||||
if previousConfig != nil {
|
||||
// If there is a previous configuration, we need to copy its extra configs to the new one.
|
||||
extraConfigs, err := extractExtraConfigs(previousConfig.AlertmanagerConfiguration)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to extract extra configs from previous configuration: %w", err)
|
||||
}
|
||||
config.ExtraConfigs = extraConfigs
|
||||
}
|
||||
|
||||
if err := moa.Crypto.ProcessSecureSettings(ctx, org, config.AlertmanagerConfig.Receivers); err != nil {
|
||||
return fmt.Errorf("failed to post process Alertmanager configuration: %w", err)
|
||||
}
|
||||
|
@ -572,3 +581,18 @@ func extractReceiverNames(rawConfig string) (sets.Set[string], error) {
|
|||
|
||||
return receiverNames, nil
|
||||
}
|
||||
|
||||
// extractExtraConfigs extracts encrypted (does not decrypt) extra configurations from the raw Alertmanager config.
|
||||
func extractExtraConfigs(rawConfig string) ([]definitions.ExtraConfiguration, error) {
|
||||
// Slimmed down version of the Alertmanager configuration to extract extra configs.
|
||||
type extraConfigUserConfig struct {
|
||||
ExtraConfigs []definitions.ExtraConfiguration `yaml:"extra_config,omitempty" json:"extra_config,omitempty"`
|
||||
}
|
||||
|
||||
cfg := &extraConfigUserConfig{}
|
||||
if err := json.Unmarshal([]byte(rawConfig), cfg); err != nil {
|
||||
return nil, fmt.Errorf("unable to parse Alertmanager configuration: %w", err)
|
||||
}
|
||||
|
||||
return cfg.ExtraConfigs, nil
|
||||
}
|
||||
|
|
|
@ -150,6 +150,264 @@ receivers:
|
|||
})
|
||||
}
|
||||
|
||||
func TestMultiOrgAlertmanager_SaveAndApplyAlertmanagerConfiguration(t *testing.T) {
|
||||
orgID := int64(1)
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("SaveAndApplyAlertmanagerConfiguration preserves existing extra configs", func(t *testing.T) {
|
||||
mam := setupMam(t, nil)
|
||||
require.NoError(t, mam.LoadAndSyncAlertmanagersForOrgs(ctx))
|
||||
|
||||
extraConfig := definitions.ExtraConfiguration{
|
||||
Identifier: "test-extra-config",
|
||||
MergeMatchers: amconfig.Matchers{&labels.Matcher{Type: labels.MatchEqual, Name: "env", Value: "test"}},
|
||||
TemplateFiles: map[string]string{"test.tmpl": "{{ define \"test\" }}Test{{ end }}"},
|
||||
AlertmanagerConfig: `route:
|
||||
receiver: extra-receiver
|
||||
receivers:
|
||||
- name: extra-receiver`,
|
||||
}
|
||||
|
||||
err := mam.SaveAndApplyExtraConfiguration(ctx, orgID, extraConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify extra config was saved
|
||||
gettableConfig, err := mam.GetAlertmanagerConfiguration(ctx, orgID, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, gettableConfig.ExtraConfigs, 1)
|
||||
require.Equal(t, extraConfig.Identifier, gettableConfig.ExtraConfigs[0].Identifier)
|
||||
|
||||
// Apply a new main configuration
|
||||
newMainConfig := definitions.PostableUserConfig{
|
||||
AlertmanagerConfig: definitions.PostableApiAlertingConfig{
|
||||
Config: definitions.Config{
|
||||
Route: &definitions.Route{
|
||||
Receiver: "main-receiver",
|
||||
},
|
||||
},
|
||||
Receivers: []*definitions.PostableApiReceiver{
|
||||
{
|
||||
Receiver: amconfig.Receiver{
|
||||
Name: "main-receiver",
|
||||
},
|
||||
PostableGrafanaReceivers: definitions.PostableGrafanaReceivers{
|
||||
GrafanaManagedReceivers: []*definitions.PostableGrafanaReceiver{
|
||||
{
|
||||
Name: "main-receiver",
|
||||
Type: "email",
|
||||
Settings: definitions.RawMessage(`{"addresses": "me@grafana.com"}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = mam.SaveAndApplyAlertmanagerConfiguration(ctx, orgID, newMainConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify that the extra config is still present after applying the new main config
|
||||
updatedConfig, err := mam.GetAlertmanagerConfiguration(ctx, orgID, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, updatedConfig.ExtraConfigs, 1)
|
||||
require.Equal(t, extraConfig.Identifier, updatedConfig.ExtraConfigs[0].Identifier)
|
||||
require.Equal(t, extraConfig.TemplateFiles, updatedConfig.ExtraConfigs[0].TemplateFiles)
|
||||
|
||||
// Verify the main config was updated
|
||||
require.Equal(t, "main-receiver", updatedConfig.AlertmanagerConfig.Route.Receiver)
|
||||
require.Len(t, updatedConfig.AlertmanagerConfig.Receivers, 1)
|
||||
require.Equal(t, "main-receiver", updatedConfig.AlertmanagerConfig.Receivers[0].Name)
|
||||
})
|
||||
|
||||
t.Run("SaveAndApplyAlertmanagerConfiguration handles missing extra_configs field", func(t *testing.T) {
|
||||
mam := setupMam(t, nil)
|
||||
require.NoError(t, mam.LoadAndSyncAlertmanagersForOrgs(ctx))
|
||||
|
||||
// Apply initial config without extra_configs field
|
||||
initialConfig := definitions.PostableUserConfig{
|
||||
AlertmanagerConfig: definitions.PostableApiAlertingConfig{
|
||||
Config: definitions.Config{
|
||||
Route: &definitions.Route{
|
||||
Receiver: "initial-receiver",
|
||||
},
|
||||
},
|
||||
Receivers: []*definitions.PostableApiReceiver{
|
||||
{
|
||||
Receiver: amconfig.Receiver{
|
||||
Name: "initial-receiver",
|
||||
},
|
||||
PostableGrafanaReceivers: definitions.PostableGrafanaReceivers{
|
||||
GrafanaManagedReceivers: []*definitions.PostableGrafanaReceiver{
|
||||
{
|
||||
Name: "initial-receiver",
|
||||
Type: "email",
|
||||
Settings: definitions.RawMessage(`{"addresses": "initial@grafana.com"}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := mam.SaveAndApplyAlertmanagerConfiguration(ctx, orgID, initialConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Apply a new main configuration
|
||||
newMainConfig := definitions.PostableUserConfig{
|
||||
AlertmanagerConfig: definitions.PostableApiAlertingConfig{
|
||||
Config: definitions.Config{
|
||||
Route: &definitions.Route{
|
||||
Receiver: "main-receiver",
|
||||
},
|
||||
},
|
||||
Receivers: []*definitions.PostableApiReceiver{
|
||||
{
|
||||
Receiver: amconfig.Receiver{
|
||||
Name: "main-receiver",
|
||||
},
|
||||
PostableGrafanaReceivers: definitions.PostableGrafanaReceivers{
|
||||
GrafanaManagedReceivers: []*definitions.PostableGrafanaReceiver{
|
||||
{
|
||||
Name: "main-receiver",
|
||||
Type: "email",
|
||||
Settings: definitions.RawMessage(`{"addresses": "me@grafana.com"}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = mam.SaveAndApplyAlertmanagerConfiguration(ctx, orgID, newMainConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify that no extra configs are present and main config was updated
|
||||
updatedConfig, err := mam.GetAlertmanagerConfiguration(ctx, orgID, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, updatedConfig.ExtraConfigs, 0)
|
||||
require.Equal(t, "main-receiver", updatedConfig.AlertmanagerConfig.Route.Receiver)
|
||||
})
|
||||
|
||||
t.Run("SaveAndApplyAlertmanagerConfiguration handles empty extra_configs array", func(t *testing.T) {
|
||||
mam := setupMam(t, nil)
|
||||
require.NoError(t, mam.LoadAndSyncAlertmanagersForOrgs(ctx))
|
||||
|
||||
// Apply initial config with empty extra_configs
|
||||
initialConfig := definitions.PostableUserConfig{
|
||||
AlertmanagerConfig: definitions.PostableApiAlertingConfig{
|
||||
Config: definitions.Config{
|
||||
Route: &definitions.Route{
|
||||
Receiver: "initial-receiver",
|
||||
},
|
||||
},
|
||||
Receivers: []*definitions.PostableApiReceiver{
|
||||
{
|
||||
Receiver: amconfig.Receiver{
|
||||
Name: "initial-receiver",
|
||||
},
|
||||
PostableGrafanaReceivers: definitions.PostableGrafanaReceivers{
|
||||
GrafanaManagedReceivers: []*definitions.PostableGrafanaReceiver{
|
||||
{
|
||||
Name: "initial-receiver",
|
||||
Type: "email",
|
||||
Settings: definitions.RawMessage(`{"addresses": "initial@grafana.com"}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExtraConfigs: []definitions.ExtraConfiguration{}, // Empty array
|
||||
}
|
||||
|
||||
err := mam.SaveAndApplyAlertmanagerConfiguration(ctx, orgID, initialConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Apply a new main configuration
|
||||
newMainConfig := definitions.PostableUserConfig{
|
||||
AlertmanagerConfig: definitions.PostableApiAlertingConfig{
|
||||
Config: definitions.Config{
|
||||
Route: &definitions.Route{
|
||||
Receiver: "main-receiver",
|
||||
},
|
||||
},
|
||||
Receivers: []*definitions.PostableApiReceiver{
|
||||
{
|
||||
Receiver: amconfig.Receiver{
|
||||
Name: "main-receiver",
|
||||
},
|
||||
PostableGrafanaReceivers: definitions.PostableGrafanaReceivers{
|
||||
GrafanaManagedReceivers: []*definitions.PostableGrafanaReceiver{
|
||||
{
|
||||
Name: "main-receiver",
|
||||
Type: "email",
|
||||
Settings: definitions.RawMessage(`{"addresses": "me@grafana.com"}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = mam.SaveAndApplyAlertmanagerConfiguration(ctx, orgID, newMainConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify that no extra configs are present and main config was updated
|
||||
updatedConfig, err := mam.GetAlertmanagerConfiguration(ctx, orgID, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, updatedConfig.ExtraConfigs, 0)
|
||||
require.Equal(t, "main-receiver", updatedConfig.AlertmanagerConfig.Route.Receiver)
|
||||
})
|
||||
}
|
||||
|
||||
func TestExtractExtraConfigs(t *testing.T) {
|
||||
t.Run("extracts extra configs from JSON", func(t *testing.T) {
|
||||
jsonConfig := `{
|
||||
"extra_config": [
|
||||
{
|
||||
"identifier": "test-config",
|
||||
"merge_matchers": [],
|
||||
"template_files": {"test.tmpl": "test"},
|
||||
"alertmanager_config": "route:\n receiver: test"
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
extraConfigs, err := extractExtraConfigs(jsonConfig)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, extraConfigs, 1)
|
||||
require.Equal(t, "test-config", extraConfigs[0].Identifier)
|
||||
})
|
||||
|
||||
t.Run("handles missing extra_config field", func(t *testing.T) {
|
||||
jsonConfig := `{"alertmanager_config": {"route": {"receiver": "test"}}}`
|
||||
|
||||
extraConfigs, err := extractExtraConfigs(jsonConfig)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, extraConfigs, 0)
|
||||
})
|
||||
|
||||
t.Run("handles empty extra_config array", func(t *testing.T) {
|
||||
jsonConfig := `{"extra_config": []}`
|
||||
|
||||
extraConfigs, err := extractExtraConfigs(jsonConfig)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, extraConfigs, 0)
|
||||
})
|
||||
|
||||
t.Run("handles null extra_config", func(t *testing.T) {
|
||||
jsonConfig := `{"extra_config": null}`
|
||||
|
||||
extraConfigs, err := extractExtraConfigs(jsonConfig)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, extraConfigs, 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMultiOrgAlertmanager_DeleteExtraConfiguration(t *testing.T) {
|
||||
orgID := int64(1)
|
||||
|
||||
|
|
Loading…
Reference in New Issue