diff --git a/pkg/services/ngalert/api/api_alertmanager.go b/pkg/services/ngalert/api/api_alertmanager.go index bdb3756de43..067077326cd 100644 --- a/pkg/services/ngalert/api/api_alertmanager.go +++ b/pkg/services/ngalert/api/api_alertmanager.go @@ -10,6 +10,7 @@ import ( "time" "github.com/go-openapi/strfmt" + alertingNotify "github.com/grafana/alerting/notify" "github.com/grafana/grafana/pkg/api/response" @@ -304,7 +305,7 @@ func (srv AlertmanagerSrv) RoutePostAlertingConfig(c *contextmodel.ReqContext, b return response.Error(http.StatusConflict, err.Error(), err) } - return ErrResp(http.StatusInternalServerError, err, "") + return response.ErrOrFallback(http.StatusInternalServerError, err.Error(), err) } func (srv AlertmanagerSrv) RouteGetReceivers(c *contextmodel.ReqContext) response.Response { diff --git a/pkg/services/ngalert/notifier/alertmanager_config.go b/pkg/services/ngalert/notifier/alertmanager_config.go index 32ae92baea2..232f17a3899 100644 --- a/pkg/services/ngalert/notifier/alertmanager_config.go +++ b/pkg/services/ngalert/notifier/alertmanager_config.go @@ -13,6 +13,20 @@ import ( "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/store" "github.com/grafana/grafana/pkg/util" + "github.com/grafana/grafana/pkg/util/errutil" +) + +var ( + // ErrAlertmanagerReceiverInUse is primarily meant for when a receiver is used by a rule and is being deleted. + ErrAlertmanagerReceiverInUse = errutil.BadRequest("alerting.notifications.alertmanager.receiverInUse").MustTemplate("receiver [Name: {{ .Public.Receiver }}] is used by rule: {{ .Error }}", + errutil.WithPublic( + "receiver [Name: {{ .Public.Receiver }}] is used by rule", + )) + // ErrAlertmanagerTimeIntervalInUse is primarily meant for when a time interval is used by a rule and is being deleted. + ErrAlertmanagerTimeIntervalInUse = errutil.BadRequest("alerting.notifications.alertmanager.intervalInUse").MustTemplate("time interval [Name: {{ .Public.Interval }}] is used by rule: {{ .Error }}", + errutil.WithPublic( + "time interval [Name: {{ .Public.Interval }}] is used by rule", + )) ) type UnknownReceiverError struct { @@ -227,6 +241,14 @@ func (moa *MultiOrgAlertmanager) SaveAndApplyAlertmanagerConfiguration(ctx conte if err := am.SaveAndApplyConfig(ctx, &config); err != nil { moa.logger.Error("Unable to save and apply alertmanager configuration", "error", err) + errReceiverDoesNotExist := ErrorReceiverDoesNotExist{} + if errors.As(err, &errReceiverDoesNotExist) { + return ErrAlertmanagerReceiverInUse.Build(errutil.TemplateData{Public: map[string]interface{}{"Receiver": errReceiverDoesNotExist.Reference}, Error: err}) + } + errTimeIntervalDoesNotExist := ErrorTimeIntervalDoesNotExist{} + if errors.As(err, &errTimeIntervalDoesNotExist) { + return ErrAlertmanagerTimeIntervalInUse.Build(errutil.TemplateData{Public: map[string]interface{}{"Interval": errTimeIntervalDoesNotExist.Reference}, Error: err}) + } return AlertmanagerConfigRejectedError{err} } diff --git a/pkg/services/ngalert/notifier/validation.go b/pkg/services/ngalert/notifier/validation.go index 48e0f20d2ad..835f2f10934 100644 --- a/pkg/services/ngalert/notifier/validation.go +++ b/pkg/services/ngalert/notifier/validation.go @@ -6,13 +6,33 @@ import ( "fmt" "sync" + "github.com/prometheus/alertmanager/config" + "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/store" - "github.com/prometheus/alertmanager/config" ) +type ErrorReferenceInvalid struct { + Reference string +} + +type ErrorReceiverDoesNotExist struct { + ErrorReferenceInvalid +} +type ErrorTimeIntervalDoesNotExist struct { + ErrorReferenceInvalid +} + +func (e ErrorReceiverDoesNotExist) Error() string { + return fmt.Sprintf("receiver %s does not exist", e.Reference) +} + +func (e ErrorTimeIntervalDoesNotExist) Error() string { + return fmt.Sprintf("time interval %s does not exist", e.Reference) +} + // NotificationSettingsValidator validates NotificationSettings against the current Alertmanager configuration type NotificationSettingsValidator interface { Validate(s models.NotificationSettings) error @@ -64,11 +84,11 @@ func (n staticValidator) Validate(settings models.NotificationSettings) error { } var errs []error if _, ok := n.availableReceivers[settings.Receiver]; !ok { - errs = append(errs, fmt.Errorf("receiver '%s' does not exist", settings.Receiver)) + errs = append(errs, ErrorReceiverDoesNotExist{ErrorReferenceInvalid: ErrorReferenceInvalid{Reference: settings.Receiver}}) } for _, interval := range settings.MuteTimeIntervals { if _, ok := n.availableTimeIntervals[interval]; !ok { - errs = append(errs, fmt.Errorf("mute time interval '%s' does not exist", interval)) + errs = append(errs, ErrorTimeIntervalDoesNotExist{ErrorReferenceInvalid: ErrorReferenceInvalid{Reference: interval}}) } } return errors.Join(errs...)