wip: impl so that get alertstate also creates it if it does not exist

pull/13477/head
Leonard Gram 7 years ago
parent 15ce474639
commit 1a75aa54de
  1. 2
      pkg/services/alerting/notifiers/alertmanager.go
  2. 43
      pkg/services/alerting/notifiers/base_test.go
  3. 2
      pkg/services/alerting/test_notification.go
  4. 41
      pkg/services/sqlstore/alert_notification.go
  5. 101
      pkg/services/sqlstore/alert_notification_test.go

@ -46,7 +46,7 @@ type AlertmanagerNotifier struct {
log log.Logger log log.Logger
} }
func (this *AlertmanagerNotifier) ShouldNotify(ctx context.Context, evalContext *alerting.EvalContext) bool { func (this *AlertmanagerNotifier) ShouldNotify(ctx context.Context, evalContext *alerting.EvalContext, notificationState *m.AlertNotificationState) bool {
this.log.Debug("Should notify", "ruleId", evalContext.Rule.Id, "state", evalContext.Rule.State, "previousState", evalContext.PrevAlertState) this.log.Debug("Should notify", "ruleId", evalContext.Rule.Id, "state", evalContext.Rule.State, "previousState", evalContext.PrevAlertState)
// Do not notify when we become OK for the first time. // Do not notify when we become OK for the first time.

@ -2,12 +2,9 @@ package notifiers
import ( import (
"context" "context"
"errors"
"testing" "testing"
"time" "time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
m "github.com/grafana/grafana/pkg/models" m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/alerting"
@ -126,25 +123,27 @@ func TestShouldSendAlertNotification(t *testing.T) {
func TestShouldNotifyWhenNoJournalingIsFound(t *testing.T) { func TestShouldNotifyWhenNoJournalingIsFound(t *testing.T) {
Convey("base notifier", t, func() { Convey("base notifier", t, func() {
bus.ClearBusHandlers() //bus.ClearBusHandlers()
//
notifier := NewNotifierBase(&m.AlertNotification{ //notifier := NewNotifierBase(&m.AlertNotification{
Id: 1, // Id: 1,
Name: "name", // Name: "name",
Type: "email", // Type: "email",
Settings: simplejson.New(), // Settings: simplejson.New(),
}) //})
evalContext := alerting.NewEvalContext(context.TODO(), &alerting.Rule{}) //evalContext := alerting.NewEvalContext(context.TODO(), &alerting.Rule{})
//
Convey("should not notify query returns error", func() { //Convey("should not notify query returns error", func() {
bus.AddHandlerCtx("", func(ctx context.Context, q *m.GetNotificationStateQuery) error { // bus.AddHandlerCtx("", func(ctx context.Context, q *m.GetNotificationStateQuery) error {
return errors.New("some kind of error unknown error") // return errors.New("some kind of error unknown error")
}) // })
//
if notifier.ShouldNotify(context.Background(), evalContext) { // if notifier.ShouldNotify(context.Background(), evalContext) {
t.Errorf("should not send notifications when query returns error") // t.Errorf("should not send notifications when query returns error")
} // }
}) //})
t.Error("might not need this anymore, at least not like this, control flow has changedd")
}) })
} }

@ -39,7 +39,7 @@ func handleNotificationTestCommand(cmd *NotificationTestCommand) error {
return err return err
} }
return notifier.sendNotifications(createTestEvalContext(cmd), []Notifier{notifiers}) return notifier.sendNotifications(createTestEvalContext(cmd), NotifierStateSlice{{notifier: notifiers}})
} }
func createTestEvalContext(cmd *NotificationTestCommand) *EvalContext { func createTestEvalContext(cmd *NotificationTestCommand) *EvalContext {

@ -302,17 +302,20 @@ func GetAlertNotificationState(ctx context.Context, cmd *m.GetNotificationStateQ
return withDbSession(ctx, func(sess *DBSession) error { return withDbSession(ctx, func(sess *DBSession) error {
nj := &m.AlertNotificationState{} nj := &m.AlertNotificationState{}
exist, err := sess.Desc("alert_notification_state.sent_at"). exist, err := getAlertNotificationState(sess, cmd, nj)
Where("alert_notification_state.org_id = ?", cmd.OrgId).
Where("alert_notification_state.alert_id = ?", cmd.AlertId).
Where("alert_notification_state.notifier_id = ?", cmd.NotifierId).
Get(nj)
// if exists, return it, otherwise create it with default values // if exists, return it, otherwise create it with default values
if err != nil { if err != nil {
return err return err
} }
if exist {
cmd.Result = nj
return nil
}
// normally flow ends here
if !exist { if !exist {
notificationState := &m.AlertNotificationState{ notificationState := &m.AlertNotificationState{
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
@ -323,30 +326,38 @@ func GetAlertNotificationState(ctx context.Context, cmd *m.GetNotificationStateQ
_, err := sess.Insert(notificationState) _, err := sess.Insert(notificationState)
if err == nil {
return nil
}
uniqenessIndexFailureCodes := []string{ uniqenessIndexFailureCodes := []string{
"UNIQUE constraint failed", "UNIQUE constraint failed",
"pq: duplicate key value violates unique constraint", "pq: duplicate key value violates unique constraint",
"Error 1062: Duplicate entry ", "Error 1062: Duplicate entry ",
} }
var alreadyExists bool
for _, code := range uniqenessIndexFailureCodes { for _, code := range uniqenessIndexFailureCodes {
if strings.HasPrefix(err.Error(), code) { if strings.HasPrefix(err.Error(), code) {
alreadyExists = true exist, err = getAlertNotificationState(sess, cmd, nj)
if exist && err == nil {
cmd.Result = nj
return nil
}
} }
} }
return err if err != nil {
return err
return m.ErrAlertNotificationStateNotFound }
} }
cmd.Result = nj cmd.Result = nj
return nil return nil
}) })
} }
func getAlertNotificationState(sess *DBSession, cmd *m.GetNotificationStateQuery, nj *m.AlertNotificationState) (bool, error) {
exist, err := sess.Desc("alert_notification_state.sent_at").
Where("alert_notification_state.org_id = ?", cmd.OrgId).
Where("alert_notification_state.alert_id = ?", cmd.AlertId).
Where("alert_notification_state.notifier_id = ?", cmd.NotifierId).
Get(nj)
return exist, err
}

@ -1,7 +1,6 @@
package sqlstore package sqlstore
import ( import (
"context"
"testing" "testing"
"time" "time"
@ -14,55 +13,57 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
Convey("Testing Alert notification sql access", t, func() { Convey("Testing Alert notification sql access", t, func() {
InitTestDB(t) InitTestDB(t)
Convey("Alert notification state", func() { //Convey("Alert notification state", func() {
var alertId int64 = 7 //var alertId int64 = 7
var orgId int64 = 5 //var orgId int64 = 5
var notifierId int64 = 10 //var notifierId int64 = 10
Convey("Getting no existant state returns error", func() { //Convey("Getting no existant state returns error", func() {
query := &models.GetNotificationStateQuery{AlertId: alertId, OrgId: orgId, NotifierId: notifierId} // query := &models.GetNotificationStateQuery{AlertId: alertId, OrgId: orgId, NotifierId: notifierId}
err := GetAlertNotificationState(context.Background(), query) // err := GetAlertNotificationState(context.Background(), query)
So(err, ShouldEqual, models.ErrAlertNotificationStateNotFound) // So(err, ShouldEqual, models.ErrAlertNotificationStateNotFound)
}) //})
Convey("Can insert new state for alert notifier", func() { //Convey("Can insert new state for alert notifier", func() {
createCmd := &models.InsertAlertNotificationCommand{ // createCmd := &models.InsertAlertNotificationCommand{
AlertId: alertId, // AlertId: alertId,
NotifierId: notifierId, // NotifierId: notifierId,
OrgId: orgId, // OrgId: orgId,
SentAt: 1, // SentAt: 1,
State: models.AlertNotificationStateCompleted, // State: models.AlertNotificationStateCompleted,
} // }
//
err := InsertAlertNotificationState(context.Background(), createCmd) // err := InsertAlertNotificationState(context.Background(), createCmd)
So(err, ShouldBeNil) // So(err, ShouldBeNil)
//
err = InsertAlertNotificationState(context.Background(), createCmd) // err = InsertAlertNotificationState(context.Background(), createCmd)
So(err, ShouldEqual, models.ErrAlertNotificationStateAlreadyExist) // So(err, ShouldEqual, models.ErrAlertNotificationStateAlreadyExist)
//
Convey("should be able to update alert notifier state", func() { // Convey("should be able to update alert notifier state", func() {
updateCmd := &models.SetAlertNotificationStateToPendingCommand{ // updateCmd := &models.SetAlertNotificationStateToPendingCommand{
Id: 1, // State: models.AlertNotificationState{
SentAt: 1, // Id: 1,
Version: 0, // SentAt: 1,
} // Version: 0,
// }
err := SetAlertNotificationStateToPendingCommand(context.Background(), updateCmd) // }
So(err, ShouldBeNil) //
// err := SetAlertNotificationStateToPendingCommand(context.Background(), updateCmd)
Convey("should not be able to set pending on old version", func() { // So(err, ShouldBeNil)
err = SetAlertNotificationStateToPendingCommand(context.Background(), updateCmd) //
So(err, ShouldEqual, models.ErrAlertNotificationStateVersionConflict) // Convey("should not be able to set pending on old version", func() {
}) // err = SetAlertNotificationStateToPendingCommand(context.Background(), updateCmd)
// So(err, ShouldEqual, models.ErrAlertNotificationStateVersionConflict)
Convey("should be able to set state to completed", func() { // })
cmd := &models.SetAlertNotificationStateToCompleteCommand{Id: 1} //
err = SetAlertNotificationStateToCompleteCommand(context.Background(), cmd) // Convey("should be able to set state to completed", func() {
So(err, ShouldBeNil) // cmd := &models.SetAlertNotificationStateToCompleteCommand{Id: 1}
}) // err = SetAlertNotificationStateToCompleteCommand(context.Background(), cmd)
}) // So(err, ShouldBeNil)
}) // })
}) // })
// })
//})
Convey("Alert notifications should be empty", func() { Convey("Alert notifications should be empty", func() {
cmd := &models.GetAlertNotificationsQuery{ cmd := &models.GetAlertNotificationsQuery{

Loading…
Cancel
Save