Alerting: Validate extra configuration with PostableApiAlertingConfig (#108706)

This commit is contained in:
Alexander Akhmetov
2025-07-28 10:09:26 +02:00
committed by GitHub
parent f4b4d8ec95
commit 4ad80cec1a
3 changed files with 127 additions and 4 deletions
@@ -1567,7 +1567,18 @@ func TestRouteConvertPrometheusPostAlertmanagerConfig(t *testing.T) {
ft := featuremgmt.WithFeatures(featuremgmt.FlagAlertingImportAlertmanagerAPI)
srv, _, _ := createConvertPrometheusSrv(t, withAlertmanager(mockAM), withFeatureToggles(ft))
amCfg := apimodels.AlertmanagerUserConfig{}
amCfg := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: `{
"route": {
"receiver": "default"
},
"receivers": [
{
"name": "default"
}
]
}`,
}
response := srv.RouteConvertPrometheusPostAlertmanagerConfig(rc, amCfg)
require.Equal(t, http.StatusAccepted, response.Status())
@@ -1585,6 +1596,26 @@ func TestRouteConvertPrometheusPostAlertmanagerConfig(t *testing.T) {
require.Equal(t, http.StatusBadRequest, response.Status())
require.Contains(t, string(response.Body()), "format should be 'key=value,key2=value2'")
})
t.Run("should return error when alertmanager config has empty route", func(t *testing.T) {
rc := createRequestCtx()
rc.Req.Header.Set(configIdentifierHeader, identifier)
rc.Req.Header.Set(mergeMatchersHeader, "env=prod")
amCfg := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: `{
"receivers": [
{
"name": "default"
}
]
}`,
}
response := srv.RouteConvertPrometheusPostAlertmanagerConfig(rc, amCfg)
require.Equal(t, http.StatusBadRequest, response.Status())
require.Contains(t, string(response.Body()), "failed to parse alertmanager config")
})
}
func TestRouteConvertPrometheusGetAlertmanagerConfig(t *testing.T) {
@@ -745,12 +745,14 @@ func (c ExtraConfiguration) Validate() error {
}
}
// Alertmanager configuration is validated during YAML unmarshalling.
am := config.Config{}
err := yaml.Unmarshal([]byte(c.AlertmanagerConfig), &am)
cfg, err := c.GetAlertmanagerConfig()
if err != nil {
return errInvalidExtraConfiguration(fmt.Errorf("failed to parse alertmanager config: %w", err))
}
err = cfg.Validate()
if err != nil {
return errInvalidExtraConfiguration(fmt.Errorf("invalid alertmanager config: %w", err))
}
return nil
}
@@ -403,3 +403,93 @@ func TestPostableUserConfig_GetMergedTemplateDefinitions(t *testing.T) {
})
}
}
func TestExtraConfiguration_Validate(t *testing.T) {
testCases := []struct {
name string
config ExtraConfiguration
expectedError string
}{
{
name: "valid configuration",
config: ExtraConfiguration{
Identifier: "test-config",
MergeMatchers: config.Matchers{{Type: labels.MatchEqual, Name: "env", Value: "prod"}},
AlertmanagerConfig: `route:
receiver: default
receivers:
- name: default`,
},
},
{
name: "empty identifier",
config: ExtraConfiguration{
Identifier: "",
MergeMatchers: config.Matchers{{Type: labels.MatchEqual, Name: "env", Value: "prod"}},
AlertmanagerConfig: `route: {receiver: default}`,
},
expectedError: "identifier is required",
},
{
name: "invalid matcher type",
config: ExtraConfiguration{
Identifier: "test-config",
MergeMatchers: config.Matchers{{Type: labels.MatchNotEqual, Name: "env", Value: "prod"}},
AlertmanagerConfig: `route:
receiver: default
receivers:
- name: default`,
},
expectedError: "only matchers with type equal are supported",
},
{
name: "invalid YAML alertmanager config",
config: ExtraConfiguration{
Identifier: "test-config",
MergeMatchers: config.Matchers{{Type: labels.MatchEqual, Name: "env", Value: "prod"}},
AlertmanagerConfig: `invalid: yaml: content: [`,
},
expectedError: "failed to parse alertmanager config",
},
{
name: "missing route in alertmanager config",
config: ExtraConfiguration{
Identifier: "test-config",
MergeMatchers: config.Matchers{{Type: labels.MatchEqual, Name: "env", Value: "prod"}},
AlertmanagerConfig: `receivers:
- name: default`,
},
expectedError: "no routes provided",
},
{
name: "missing receivers in alertmanager config",
config: ExtraConfiguration{
Identifier: "test-config",
MergeMatchers: config.Matchers{{Type: labels.MatchEqual, Name: "env", Value: "prod"}},
AlertmanagerConfig: `route:
receiver: default`,
},
expectedError: "undefined receiver",
},
{
name: "empty alertmanager config",
config: ExtraConfiguration{
Identifier: "test-config",
MergeMatchers: config.Matchers{{Type: labels.MatchEqual, Name: "env", Value: "prod"}},
AlertmanagerConfig: "",
},
expectedError: "failed to parse alertmanager config",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := tc.config.Validate()
if tc.expectedError == "" {
require.NoError(t, err)
} else {
require.ErrorContains(t, err, tc.expectedError)
}
})
}
}