diff --git a/pkg/alertmanager/api_grafana.go b/pkg/alertmanager/api_grafana.go index 0f52e9c3f07..7c4105ec177 100644 --- a/pkg/alertmanager/api_grafana.go +++ b/pkg/alertmanager/api_grafana.go @@ -17,7 +17,9 @@ import ( "github.com/grafana/mimir/pkg/alertmanager/alertspb" "github.com/grafana/mimir/pkg/util" + "github.com/grafana/mimir/pkg/util/globalerror" util_log "github.com/grafana/mimir/pkg/util/log" + "github.com/grafana/mimir/pkg/util/validation" ) const ( @@ -38,6 +40,17 @@ const ( statusError = "error" ) +var ( + maxGrafanaConfigSizeMsgFormat = globalerror.AlertmanagerMaxGrafanaConfigSize.MessageWithPerTenantLimitConfig( + errConfigurationTooBig, + validation.AlertmanagerMaxGrafanaConfigSizeFlag, + ) + maxGrafanaStateSizeMsgFormat = globalerror.AlertmanagerMaxGrafanaStateSize.MessageWithPerTenantLimitConfig( + errStateTooBig, + validation.AlertmanagerMaxGrafanaStateSizeFlag, + ) +) + type GrafanaAlertmanagerConfig struct { Templates map[string]string `json:"template_files"` AlertmanagerConfig definition.PostableApiAlertingConfig `json:"alertmanager_config"` @@ -180,10 +193,12 @@ func (am *MultitenantAlertmanager) SetUserGrafanaState(w http.ResponseWriter, r payload, err := io.ReadAll(input) if err != nil { if maxBytesErr := (&http.MaxBytesError{}); errors.As(err, &maxBytesErr) { - msg := fmt.Sprintf(errStateTooBig, maxStateSize) - level.Warn(logger).Log("msg", msg) + level.Warn(logger).Log("msg", fmt.Sprintf(errStateTooBig, maxStateSize)) w.WriteHeader(http.StatusBadRequest) - util.WriteJSONResponse(w, errorResult{Status: statusError, Error: msg}) + util.WriteJSONResponse(w, errorResult{ + Status: statusError, + Error: fmt.Sprintf(maxGrafanaStateSizeMsgFormat, maxStateSize), + }) return } @@ -336,10 +351,12 @@ func (am *MultitenantAlertmanager) SetUserGrafanaConfig(w http.ResponseWriter, r payload, err := io.ReadAll(input) if err != nil { if maxBytesErr := (&http.MaxBytesError{}); errors.As(err, &maxBytesErr) { - msg := fmt.Sprintf(errConfigurationTooBig, maxConfigSize) - level.Warn(logger).Log("msg", msg) + level.Warn(logger).Log("msg", fmt.Sprintf(errConfigurationTooBig, maxConfigSize)) w.WriteHeader(http.StatusBadRequest) - util.WriteJSONResponse(w, errorResult{Status: statusError, Error: msg}) + util.WriteJSONResponse(w, errorResult{ + Status: statusError, + Error: fmt.Sprintf(maxGrafanaConfigSizeMsgFormat, maxConfigSize), + }) return } diff --git a/pkg/alertmanager/api_grafana_test.go b/pkg/alertmanager/api_grafana_test.go index 77c3463165a..7e40ce7da5c 100644 --- a/pkg/alertmanager/api_grafana_test.go +++ b/pkg/alertmanager/api_grafana_test.go @@ -342,7 +342,7 @@ func TestMultitenantAlertmanager_SetUserGrafanaConfig(t *testing.T) { expStatusCode: http.StatusBadRequest, expResponseBody: ` { - "error": "Alertmanager configuration is too big, limit: 10 bytes", + "error": "Alertmanager configuration is too big, limit: 10 bytes (err-mimir-alertmanager-max-grafana-config-size). To adjust the related per-tenant limit, configure -alertmanager.max-grafana-config-size-bytes, or contact your service administrator.", "status": "error" } `, @@ -459,7 +459,7 @@ func TestMultitenantAlertmanager_SetUserGrafanaState(t *testing.T) { expStatusCode: http.StatusBadRequest, expResponseBody: ` { - "error": "Alertmanager state is too big, limit: 10 bytes", + "error": "Alertmanager state is too big, limit: 10 bytes (err-mimir-alertmanager-max-grafana-state-size). To adjust the related per-tenant limit, configure -alertmanager.max-grafana-state-size-bytes, or contact your service administrator.", "status": "error" } `, diff --git a/pkg/util/globalerror/user.go b/pkg/util/globalerror/user.go index a0139601bd6..6985ee0fea5 100644 --- a/pkg/util/globalerror/user.go +++ b/pkg/util/globalerror/user.go @@ -85,6 +85,10 @@ const ( NativeHistogramNegativeBucketCount ID = "native-histogram-negative-bucket-count" NativeHistogramSpanNegativeOffset ID = "native-histogram-span-negative-offset" NativeHistogramSpansBucketsMismatch ID = "native-histogram-spans-buckets-mismatch" + + // Alertmanager errors + AlertmanagerMaxGrafanaConfigSize ID = "alertmanager-max-grafana-config-size" + AlertmanagerMaxGrafanaStateSize ID = "alertmanager-max-grafana-state-size" ) // Message returns the provided msg, appending the error id. diff --git a/pkg/util/validation/limits.go b/pkg/util/validation/limits.go index 35c94bc176b..16b1e3685c8 100644 --- a/pkg/util/validation/limits.go +++ b/pkg/util/validation/limits.go @@ -59,6 +59,8 @@ const ( resultsCacheTTLForOutOfOrderWindowFlag = "query-frontend.results-cache-ttl-for-out-of-order-time-window" alignQueriesWithStepFlag = "query-frontend.align-queries-with-step" QueryIngestersWithinFlag = "querier.query-ingesters-within" + AlertmanagerMaxGrafanaConfigSizeFlag = "alertmanager.max-grafana-config-size-bytes" + AlertmanagerMaxGrafanaStateSizeFlag = "alertmanager.max-grafana-state-size-bytes" // MinCompactorPartialBlockDeletionDelay is the minimum partial blocks deletion delay that can be configured in Mimir. MinCompactorPartialBlockDeletionDelay = 4 * time.Hour