diff --git a/pkg/models/alert_notifications.go b/pkg/models/alert_notifications.go index 85fdbafe9c4..3ac23438b8e 100644 --- a/pkg/models/alert_notifications.go +++ b/pkg/models/alert_notifications.go @@ -7,30 +7,33 @@ import ( ) type AlertNotification struct { - Id int64 `json:"id"` - OrgId int64 `json:"-"` - Name string `json:"name"` - Type string `json:"type"` - Settings *simplejson.Json `json:"settings"` - Created time.Time `json:"created"` - Updated time.Time `json:"updated"` + Id int64 `json:"id"` + OrgId int64 `json:"-"` + Name string `json:"name"` + Type string `json:"type"` + AlwaysExecute bool `json:"alwaysExecute"` + Settings *simplejson.Json `json:"settings"` + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` } type CreateAlertNotificationCommand struct { - Name string `json:"name" binding:"Required"` - Type string `json:"type" binding:"Required"` - OrgID int64 `json:"-"` - Settings *simplejson.Json `json:"settings"` + Name string `json:"name" binding:"Required"` + Type string `json:"type" binding:"Required"` + AlwaysExecute bool `json:"alwaysExecute"` + OrgID int64 `json:"-"` + Settings *simplejson.Json `json:"settings"` Result *AlertNotification } type UpdateAlertNotificationCommand struct { - Id int64 `json:"id" binding:"Required"` - Name string `json:"name" binding:"Required"` - Type string `json:"type" binding:"Required"` - OrgID int64 `json:"-"` - Settings *simplejson.Json `json:"settings" binding:"Required"` + Id int64 `json:"id" binding:"Required"` + Name string `json:"name" binding:"Required"` + Type string `json:"type" binding:"Required"` + AlwaysExecute bool `json:"alwaysExecute"` + OrgID int64 `json:"-"` + Settings *simplejson.Json `json:"settings" binding:"Required"` Result *AlertNotification } @@ -41,10 +44,11 @@ type DeleteAlertNotificationCommand struct { } type GetAlertNotificationQuery struct { - Name string - Id int64 - Ids []int64 - OrgID int64 + Name string + Id int64 + Ids []int64 + OrgID int64 + IncludeAlwaysExecute bool Result []*AlertNotification } diff --git a/pkg/services/alerting/alert_rule.go b/pkg/services/alerting/alert_rule.go index 2fcfac64cfb..77f21255156 100644 --- a/pkg/services/alerting/alert_rule.go +++ b/pkg/services/alerting/alert_rule.go @@ -63,6 +63,8 @@ func NewAlertRuleFromDBModel(ruleDef *m.Alert) (*AlertRule, error) { model.State = ruleDef.State model.Frequency = ruleDef.Frequency + model.NotificationGroups = []int64{1, 2} + critical := ruleDef.Settings.Get("crit") model.Critical = Level{ Operator: critical.Get("op").MustString(), diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go index f9462038b50..57da39b88e9 100644 --- a/pkg/services/alerting/notifier.go +++ b/pkg/services/alerting/notifier.go @@ -22,12 +22,12 @@ func NewNotifier() *NotifierImpl { } func (n *NotifierImpl) Notify(alertResult *AlertResult) { - notifiers := n.getNotifiers(alertResult.AlertJob.Rule.OrgId, []int64{1, 2}) + notifiers := n.getNotifiers(alertResult.AlertJob.Rule.OrgId, alertResult.AlertJob.Rule.NotificationGroups) for _, notifier := range notifiers { warn := alertResult.State == alertstates.Warn && notifier.SendWarning crit := alertResult.State == alertstates.Critical && notifier.SendCritical - if warn || crit { + if (warn || crit) || alertResult.State == alertstates.Ok { n.log.Info("Sending notification", "state", alertResult.State, "type", notifier.Type) go notifier.Notifierr.Dispatch(alertResult) } @@ -109,8 +109,9 @@ type NotificationDispatcher interface { func (n *NotifierImpl) getNotifiers(orgId int64, notificationGroups []int64) []*Notification { query := &m.GetAlertNotificationQuery{ - OrgID: orgId, - Ids: notificationGroups, + OrgID: orgId, + Ids: notificationGroups, + IncludeAlwaysExecute: true, } err := bus.Dispatch(query) if err != nil { @@ -118,11 +119,13 @@ func (n *NotifierImpl) getNotifiers(orgId int64, notificationGroups []int64) []* } var result []*Notification - + n.log.Info("notifiriring", "count", len(query.Result), "groups", notificationGroups) for _, notification := range query.Result { not, err := NewNotificationFromDBModel(notification) if err == nil { result = append(result, not) + } else { + n.log.Error("Failed to read notification model", "error", err) } } diff --git a/pkg/services/notifications/send_email_integration_test.go b/pkg/services/notifications/send_email_integration_test.go index 74e9cb5a68d..7795921c3b7 100644 --- a/pkg/services/notifications/send_email_integration_test.go +++ b/pkg/services/notifications/send_email_integration_test.go @@ -22,9 +22,7 @@ func TestEmailIntegrationTest(t *testing.T) { err := Init() So(err, ShouldBeNil) - var sentMsg *Message addToMailQueue = func(msg *Message) { - sentMsg = msg ioutil.WriteFile("../../../tmp/test_email.html", []byte(msg.Body), 0777) } diff --git a/pkg/services/sqlstore/alert_notification.go b/pkg/services/sqlstore/alert_notification.go index 4c4bdb6e4c4..e40d2ba419c 100644 --- a/pkg/services/sqlstore/alert_notification.go +++ b/pkg/services/sqlstore/alert_notification.go @@ -46,7 +46,8 @@ func getAlertNotifications(query *m.GetAlertNotificationQuery, sess *xorm.Sessio alert_notification.type, alert_notification.created, alert_notification.updated, - alert_notification.settings + alert_notification.settings, + alert_notification.always_execute FROM alert_notification `) @@ -77,18 +78,43 @@ func getAlertNotifications(query *m.GetAlertNotificationQuery, sess *xorm.Sessio sql.WriteString(`)`) } - var result []*m.AlertNotification - if err := sess.Sql(sql.String(), params...).Find(&result); err != nil { + var searches []*m.AlertNotification + if err := sess.Sql(sql.String(), params...).Find(&searches); err != nil { return err } + var result []*m.AlertNotification + var def []*m.AlertNotification + if query.IncludeAlwaysExecute { + + if err := sess.Where("org_id = ? AND always_execute = 1", query.OrgID).Find(&def); err != nil { + return err + } + + result = append(result, def...) + } + + for _, s := range searches { + canAppend := true + for _, d := range result { + if d.Id == s.Id { + canAppend = false + break + } + } + + if canAppend { + result = append(result, s) + } + } + query.Result = result return nil } func CreateAlertNotificationCommand(cmd *m.CreateAlertNotificationCommand) error { return inTransaction(func(sess *xorm.Session) error { - existingQuery := &m.GetAlertNotificationQuery{OrgID: cmd.OrgID, Name: cmd.Name} + existingQuery := &m.GetAlertNotificationQuery{OrgID: cmd.OrgID, Name: cmd.Name, IncludeAlwaysExecute: false} err := getAlertNotifications(existingQuery, sess) if err != nil { @@ -100,12 +126,13 @@ func CreateAlertNotificationCommand(cmd *m.CreateAlertNotificationCommand) error } alertNotification := &m.AlertNotification{ - OrgId: cmd.OrgID, - Name: cmd.Name, - Type: cmd.Type, - Created: time.Now(), - Settings: cmd.Settings, - Updated: time.Now(), + OrgId: cmd.OrgID, + Name: cmd.Name, + Type: cmd.Type, + Created: time.Now(), + Settings: cmd.Settings, + Updated: time.Now(), + AlwaysExecute: cmd.AlwaysExecute, } _, err = sess.Insert(alertNotification) @@ -114,7 +141,6 @@ func CreateAlertNotificationCommand(cmd *m.CreateAlertNotificationCommand) error return err } - //alertNotification.Id = int(id) cmd.Result = alertNotification return nil }) @@ -137,9 +163,9 @@ func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error { alertNotification.Settings = cmd.Settings alertNotification.Updated = time.Now() alertNotification.Created = current.Created + alertNotification.AlwaysExecute = cmd.AlwaysExecute var affected int64 - //affected, err = sess.Id(alertNotification.Id).Cols("name", "type", "settings", "updated").Update(alertNotification) affected, err = sess.Id(alertNotification.Id).Update(alertNotification) if err != nil { diff --git a/pkg/services/sqlstore/alert_notification_test.go b/pkg/services/sqlstore/alert_notification_test.go index 0b5b8e8cf13..ea0f487aa1e 100644 --- a/pkg/services/sqlstore/alert_notification_test.go +++ b/pkg/services/sqlstore/alert_notification_test.go @@ -28,10 +28,11 @@ func TestAlertNotificationSQLAccess(t *testing.T) { Convey("Can save Alert Notification", func() { cmd := &m.CreateAlertNotificationCommand{ - Name: "ops", - Type: "email", - OrgID: 1, - Settings: simplejson.New(), + Name: "ops", + Type: "email", + OrgID: 1, + Settings: simplejson.New(), + AlwaysExecute: true, } err = CreateAlertNotificationCommand(cmd) @@ -39,6 +40,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) { So(cmd.Result.Id, ShouldNotEqual, 0) So(cmd.Result.OrgId, ShouldNotEqual, 0) So(cmd.Result.Type, ShouldEqual, "email") + So(cmd.Result.AlwaysExecute, ShouldEqual, true) Convey("Cannot save Alert Notification with the same name", func() { err = CreateAlertNotificationCommand(cmd) @@ -47,11 +49,12 @@ func TestAlertNotificationSQLAccess(t *testing.T) { Convey("Can update alert notification", func() { newCmd := &m.UpdateAlertNotificationCommand{ - Name: "NewName", - Type: "webhook", - OrgID: cmd.Result.OrgId, - Settings: simplejson.New(), - Id: cmd.Result.Id, + Name: "NewName", + Type: "webhook", + OrgID: cmd.Result.OrgId, + Settings: simplejson.New(), + Id: cmd.Result.Id, + AlwaysExecute: true, } err := UpdateAlertNotification(newCmd) So(err, ShouldBeNil) @@ -60,6 +63,14 @@ func TestAlertNotificationSQLAccess(t *testing.T) { }) Convey("Can search using an array of ids", func() { + So(CreateAlertNotificationCommand(&m.CreateAlertNotificationCommand{ + Name: "nagios", + Type: "webhook", + OrgID: 1, + Settings: simplejson.New(), + AlwaysExecute: true, + }), ShouldBeNil) + So(CreateAlertNotificationCommand(&m.CreateAlertNotificationCommand{ Name: "ops2", Type: "email", @@ -75,14 +86,26 @@ func TestAlertNotificationSQLAccess(t *testing.T) { }), ShouldBeNil) Convey("search", func() { + existingNotification := int64(2) + missingThatSholdNotCauseerrors := int64(99) + query := &m.GetAlertNotificationQuery{ - Ids: []int64{1, 2, 3}, - OrgID: 1, + Ids: []int64{existingNotification, missingThatSholdNotCauseerrors}, + OrgID: 1, + IncludeAlwaysExecute: true, } err := AlertNotificationQuery(query) So(err, ShouldBeNil) So(len(query.Result), ShouldEqual, 2) + defaultNotifications := 0 + for _, not := range query.Result { + if not.AlwaysExecute { + defaultNotifications++ + } + } + + So(defaultNotifications, ShouldEqual, 1) }) }) }) diff --git a/pkg/services/sqlstore/migrations/alert_mig.go b/pkg/services/sqlstore/migrations/alert_mig.go index c49319c1c9a..a6c5f49cda1 100644 --- a/pkg/services/sqlstore/migrations/alert_mig.go +++ b/pkg/services/sqlstore/migrations/alert_mig.go @@ -74,6 +74,7 @@ func addAlertMigrations(mg *Migrator) { {Name: "org_id", Type: DB_BigInt, Nullable: false}, {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "always_execute", Type: DB_Bool, Nullable: false}, {Name: "settings", Type: DB_Text, Nullable: false}, {Name: "created", Type: DB_DateTime, Nullable: false}, {Name: "updated", Type: DB_DateTime, Nullable: false},