Skip to content

Commit

Permalink
Alerting: Improve error when receiver or time interval used by rule i…
Browse files Browse the repository at this point in the history
…s 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
  • Loading branch information
JacobsonMT committed Apr 25, 2024
1 parent e394e16 commit 3397e8b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 4 deletions.
3 changes: 2 additions & 1 deletion pkg/services/ngalert/api/api_alertmanager.go
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/go-openapi/strfmt"

alertingNotify "github.com/grafana/alerting/notify"

"github.com/grafana/grafana/pkg/api/response"
Expand Down Expand Up @@ -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 {
Expand Down
22 changes: 22 additions & 0 deletions pkg/services/ngalert/notifier/alertmanager_config.go
Expand Up @@ -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 {
Expand Down Expand Up @@ -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}
}

Expand Down
26 changes: 23 additions & 3 deletions pkg/services/ngalert/notifier/validation.go
Expand Up @@ -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
Expand Down Expand Up @@ -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...)
Expand Down

0 comments on commit 3397e8b

Please sign in to comment.