Alerting: Improve error when receiver or time interval used by rule is deleted (#86865)

* Alerting: Improve error when receiver used by rule is deleted

* Remove RuleUID from public error and data

* Improve fallback error in am config post

* Refactor to expand to time intervals

* Fix message on unchecked errors to be same as before
This commit is contained in:
Matthew Jacobson 2024-04-25 13:36:00 -04:00 committed by GitHub
parent e394e16073
commit 3397e8bf09
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 47 additions and 4 deletions

View File

@ -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 {

View File

@ -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}
}

View File

@ -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...)