John Baublitz 7 роки тому
батько
коміт
fca97535d1

+ 48 - 9
pkg/api/alerting.go

@@ -193,12 +193,15 @@ func GetAlertNotifications(c *m.ReqContext) Response {
 
 
 	for _, notification := range query.Result {
 	for _, notification := range query.Result {
 		result = append(result, &dtos.AlertNotification{
 		result = append(result, &dtos.AlertNotification{
-			Id:        notification.Id,
-			Name:      notification.Name,
-			Type:      notification.Type,
-			IsDefault: notification.IsDefault,
-			Created:   notification.Created,
-			Updated:   notification.Updated,
+			Id:         notification.Id,
+			Name:       notification.Name,
+			Type:       notification.Type,
+			IsDefault:  notification.IsDefault,
+			Created:    notification.Created,
+			Updated:    notification.Updated,
+			Frequency:  notification.Frequency.String(),
+			NotifyOnce: notification.NotifyOnce,
+			Settings:   notification.Settings,
 		})
 		})
 	}
 	}
 
 
@@ -215,7 +218,19 @@ func GetAlertNotificationByID(c *m.ReqContext) Response {
 		return Error(500, "Failed to get alert notifications", err)
 		return Error(500, "Failed to get alert notifications", err)
 	}
 	}
 
 
-	return JSON(200, query.Result)
+	result := &dtos.AlertNotification{
+		Id:         query.Result.Id,
+		Name:       query.Result.Name,
+		Type:       query.Result.Type,
+		IsDefault:  query.Result.IsDefault,
+		Created:    query.Result.Created,
+		Updated:    query.Result.Updated,
+		Frequency:  query.Result.Frequency.String(),
+		NotifyOnce: query.Result.NotifyOnce,
+		Settings:   query.Result.Settings,
+	}
+
+	return JSON(200, result)
 }
 }
 
 
 func CreateAlertNotification(c *m.ReqContext, cmd m.CreateAlertNotificationCommand) Response {
 func CreateAlertNotification(c *m.ReqContext, cmd m.CreateAlertNotificationCommand) Response {
@@ -225,7 +240,19 @@ func CreateAlertNotification(c *m.ReqContext, cmd m.CreateAlertNotificationComma
 		return Error(500, "Failed to create alert notification", err)
 		return Error(500, "Failed to create alert notification", err)
 	}
 	}
 
 
-	return JSON(200, cmd.Result)
+	result := &dtos.AlertNotification{
+		Id:         cmd.Result.Id,
+		Name:       cmd.Result.Name,
+		Type:       cmd.Result.Type,
+		IsDefault:  cmd.Result.IsDefault,
+		Created:    cmd.Result.Created,
+		Updated:    cmd.Result.Updated,
+		Frequency:  cmd.Result.Frequency.String(),
+		NotifyOnce: cmd.Result.NotifyOnce,
+		Settings:   cmd.Result.Settings,
+	}
+
+	return JSON(200, result)
 }
 }
 
 
 func UpdateAlertNotification(c *m.ReqContext, cmd m.UpdateAlertNotificationCommand) Response {
 func UpdateAlertNotification(c *m.ReqContext, cmd m.UpdateAlertNotificationCommand) Response {
@@ -235,7 +262,19 @@ func UpdateAlertNotification(c *m.ReqContext, cmd m.UpdateAlertNotificationComma
 		return Error(500, "Failed to update alert notification", err)
 		return Error(500, "Failed to update alert notification", err)
 	}
 	}
 
 
-	return JSON(200, cmd.Result)
+	result := &dtos.AlertNotification{
+		Id:         cmd.Result.Id,
+		Name:       cmd.Result.Name,
+		Type:       cmd.Result.Type,
+		IsDefault:  cmd.Result.IsDefault,
+		Created:    cmd.Result.Created,
+		Updated:    cmd.Result.Updated,
+		Frequency:  cmd.Result.Frequency.String(),
+		NotifyOnce: cmd.Result.NotifyOnce,
+		Settings:   cmd.Result.Settings,
+	}
+
+	return JSON(200, result)
 }
 }
 
 
 func DeleteAlertNotification(c *m.ReqContext) Response {
 func DeleteAlertNotification(c *m.ReqContext) Response {

+ 10 - 9
pkg/api/dtos/alerting.go

@@ -24,14 +24,15 @@ type AlertRule struct {
 }
 }
 
 
 type AlertNotification struct {
 type AlertNotification struct {
-	Id         int64     `json:"id"`
-	Name       string    `json:"name"`
-	Type       string    `json:"type"`
-	IsDefault  bool      `json:"isDefault"`
-	NotifyOnce bool      `json:"notifyOnce"`
-	Frequency  bool      `json:"frequency"`
-	Created    time.Time `json:"created"`
-	Updated    time.Time `json:"updated"`
+	Id         int64            `json:"id"`
+	Name       string           `json:"name"`
+	Type       string           `json:"type"`
+	IsDefault  bool             `json:"isDefault"`
+	NotifyOnce bool             `json:"notifyOnce"`
+	Frequency  string           `json:"frequency"`
+	Created    time.Time        `json:"created"`
+	Updated    time.Time        `json:"updated"`
+	Settings   *simplejson.Json `json:"settings"`
 }
 }
 
 
 type AlertTestCommand struct {
 type AlertTestCommand struct {
@@ -64,7 +65,7 @@ type NotificationTestCommand struct {
 	Name       string           `json:"name"`
 	Name       string           `json:"name"`
 	Type       string           `json:"type"`
 	Type       string           `json:"type"`
 	NotifyOnce bool             `json:"notifyOnce"`
 	NotifyOnce bool             `json:"notifyOnce"`
-	Frequency  time.Duration    `json:"frequency"`
+	Frequency  string           `json:"frequency"`
 	Settings   *simplejson.Json `json:"settings"`
 	Settings   *simplejson.Json `json:"settings"`
 }
 }
 
 

+ 3 - 3
pkg/models/alert_notifications.go

@@ -22,8 +22,8 @@ type AlertNotification struct {
 type CreateAlertNotificationCommand struct {
 type CreateAlertNotificationCommand struct {
 	Name       string           `json:"name"  binding:"Required"`
 	Name       string           `json:"name"  binding:"Required"`
 	Type       string           `json:"type"  binding:"Required"`
 	Type       string           `json:"type"  binding:"Required"`
-	NotifyOnce bool             `json:"notifyOnce"  binding:"Required"`
-	Frequency  time.Duration    `json:"frequency"`
+	NotifyOnce bool             `json:"notifyOnce"`
+	Frequency  string           `json:"frequency"`
 	IsDefault  bool             `json:"isDefault"`
 	IsDefault  bool             `json:"isDefault"`
 	Settings   *simplejson.Json `json:"settings"`
 	Settings   *simplejson.Json `json:"settings"`
 
 
@@ -35,7 +35,7 @@ type UpdateAlertNotificationCommand struct {
 	Id         int64            `json:"id"  binding:"Required"`
 	Id         int64            `json:"id"  binding:"Required"`
 	Name       string           `json:"name"  binding:"Required"`
 	Name       string           `json:"name"  binding:"Required"`
 	Type       string           `json:"type"  binding:"Required"`
 	Type       string           `json:"type"  binding:"Required"`
-	NotifyOnce string           `json:"notifyOnce"  binding:"Required"`
+	NotifyOnce bool             `json:"notifyOnce"`
 	Frequency  string           `json:"frequency"`
 	Frequency  string           `json:"frequency"`
 	IsDefault  bool             `json:"isDefault"`
 	IsDefault  bool             `json:"isDefault"`
 	Settings   *simplejson.Json `json:"settings"  binding:"Required"`
 	Settings   *simplejson.Json `json:"settings"  binding:"Required"`

+ 2 - 2
pkg/services/alerting/eval_context.go

@@ -151,8 +151,8 @@ func (c *EvalContext) LastNotify(notifierId int64) *time.Time {
 		NotifierId: notifierId,
 		NotifierId: notifierId,
 	}
 	}
 	if err := bus.Dispatch(cmd); err != nil {
 	if err := bus.Dispatch(cmd); err != nil {
-		c.log.Warn("Could not determine last time alert",
-			c.Rule.Name, "notified")
+		c.log.Warn("Could not determine last time alert notifier fired",
+			"Alert name", c.Rule.Name, "Error", err)
 		return nil
 		return nil
 	}
 	}
 
 

+ 1 - 0
pkg/services/alerting/notifiers/base.go

@@ -41,6 +41,7 @@ func defaultShouldNotify(context *alerting.EvalContext, notifyOnce bool, frequen
 	if context.PrevAlertState == context.Rule.State && notifyOnce {
 	if context.PrevAlertState == context.Rule.State && notifyOnce {
 		return false
 		return false
 	}
 	}
+	// Do not notify if interval has not elapsed
 	if !notifyOnce && lastNotify != nil && lastNotify.Add(frequency).After(time.Now()) {
 	if !notifyOnce && lastNotify != nil && lastNotify.Add(frequency).After(time.Now()) {
 		return false
 		return false
 	}
 	}

+ 8 - 5
pkg/services/alerting/notifiers/base_test.go

@@ -3,6 +3,7 @@ package notifiers
 import (
 import (
 	"context"
 	"context"
 	"testing"
 	"testing"
+	"time"
 
 
 	"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"
@@ -18,19 +19,19 @@ func TestBaseNotifier(t *testing.T) {
 			Convey("can parse false value", func() {
 			Convey("can parse false value", func() {
 				bJson.Set("uploadImage", false)
 				bJson.Set("uploadImage", false)
 
 
-				base := NewNotifierBase(1, false, "name", "email", bJson)
+				base := NewNotifierBase(1, false, "name", "email", true, 0, bJson)
 				So(base.UploadImage, ShouldBeFalse)
 				So(base.UploadImage, ShouldBeFalse)
 			})
 			})
 
 
 			Convey("can parse true value", func() {
 			Convey("can parse true value", func() {
 				bJson.Set("uploadImage", true)
 				bJson.Set("uploadImage", true)
 
 
-				base := NewNotifierBase(1, false, "name", "email", bJson)
+				base := NewNotifierBase(1, false, "name", "email", true, 0, bJson)
 				So(base.UploadImage, ShouldBeTrue)
 				So(base.UploadImage, ShouldBeTrue)
 			})
 			})
 
 
 			Convey("default value should be true for backwards compatibility", func() {
 			Convey("default value should be true for backwards compatibility", func() {
-				base := NewNotifierBase(1, false, "name", "email", bJson)
+				base := NewNotifierBase(1, false, "name", "email", true, 0, bJson)
 				So(base.UploadImage, ShouldBeTrue)
 				So(base.UploadImage, ShouldBeTrue)
 			})
 			})
 		})
 		})
@@ -41,7 +42,8 @@ func TestBaseNotifier(t *testing.T) {
 					State: m.AlertStatePending,
 					State: m.AlertStatePending,
 				})
 				})
 				context.Rule.State = m.AlertStateOK
 				context.Rule.State = m.AlertStateOK
-				So(defaultShouldNotify(context), ShouldBeFalse)
+				timeNow := time.Now()
+				So(defaultShouldNotify(context, true, 0, &timeNow), ShouldBeFalse)
 			})
 			})
 
 
 			Convey("ok -> alerting", func() {
 			Convey("ok -> alerting", func() {
@@ -49,7 +51,8 @@ func TestBaseNotifier(t *testing.T) {
 					State: m.AlertStateOK,
 					State: m.AlertStateOK,
 				})
 				})
 				context.Rule.State = m.AlertStateAlerting
 				context.Rule.State = m.AlertStateAlerting
-				So(defaultShouldNotify(context), ShouldBeTrue)
+				timeNow := time.Now()
+				So(defaultShouldNotify(context, true, 0, &timeNow), ShouldBeTrue)
 			})
 			})
 		})
 		})
 	})
 	})

+ 22 - 6
pkg/services/sqlstore/alert_notification.go

@@ -56,7 +56,9 @@ func GetAlertNotificationsToSend(query *m.GetAlertNotificationsToSendQuery) erro
 										alert_notification.created,
 										alert_notification.created,
 										alert_notification.updated,
 										alert_notification.updated,
 										alert_notification.settings,
 										alert_notification.settings,
-										alert_notification.is_default
+										alert_notification.is_default,
+										alert_notification.notify_once,
+										alert_notification.frequency
 										FROM alert_notification
 										FROM alert_notification
 	  							`)
 	  							`)
 
 
@@ -94,7 +96,9 @@ func getAlertNotificationInternal(query *m.GetAlertNotificationsQuery, sess *DBS
 										alert_notification.created,
 										alert_notification.created,
 										alert_notification.updated,
 										alert_notification.updated,
 										alert_notification.settings,
 										alert_notification.settings,
-										alert_notification.is_default
+										alert_notification.is_default,
+										alert_notification.notify_once,
+										alert_notification.frequency
 										FROM alert_notification
 										FROM alert_notification
 	  							`)
 	  							`)
 
 
@@ -140,19 +144,24 @@ func CreateAlertNotificationCommand(cmd *m.CreateAlertNotificationCommand) error
 			return fmt.Errorf("Alert notification name %s already exists", cmd.Name)
 			return fmt.Errorf("Alert notification name %s already exists", cmd.Name)
 		}
 		}
 
 
+		frequency, err_convert := time.ParseDuration(cmd.Frequency)
+		if err_convert != nil {
+			return err
+		}
+
 		alertNotification := &m.AlertNotification{
 		alertNotification := &m.AlertNotification{
 			OrgId:      cmd.OrgId,
 			OrgId:      cmd.OrgId,
 			Name:       cmd.Name,
 			Name:       cmd.Name,
 			Type:       cmd.Type,
 			Type:       cmd.Type,
 			Settings:   cmd.Settings,
 			Settings:   cmd.Settings,
 			NotifyOnce: cmd.NotifyOnce,
 			NotifyOnce: cmd.NotifyOnce,
-			Frequency:  cmd.Frequency,
+			Frequency:  frequency,
 			Created:    time.Now(),
 			Created:    time.Now(),
 			Updated:    time.Now(),
 			Updated:    time.Now(),
 			IsDefault:  cmd.IsDefault,
 			IsDefault:  cmd.IsDefault,
 		}
 		}
 
 
-		if _, err = sess.Insert(alertNotification); err != nil {
+		if _, err = sess.MustCols("notify_once").Insert(alertNotification); err != nil {
 			return err
 			return err
 		}
 		}
 
 
@@ -184,8 +193,15 @@ func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error {
 		current.Name = cmd.Name
 		current.Name = cmd.Name
 		current.Type = cmd.Type
 		current.Type = cmd.Type
 		current.IsDefault = cmd.IsDefault
 		current.IsDefault = cmd.IsDefault
+		current.NotifyOnce = cmd.NotifyOnce
+
+		frequency, err_convert := time.ParseDuration(cmd.Frequency)
+		if err_convert != nil {
+			return err
+		}
+		current.Frequency = frequency
 
 
-		sess.UseBool("is_default")
+		sess.UseBool("is_default", "notify_once")
 
 
 		if affected, err := sess.ID(cmd.Id).Update(current); err != nil {
 		if affected, err := sess.ID(cmd.Id).Update(current); err != nil {
 			return err
 			return err
@@ -219,7 +235,7 @@ func RecordNotificationJournal(cmd *m.RecordNotificationJournalCommand) error {
 func GetLatestNotification(cmd *m.GetLatestNotificationQuery) error {
 func GetLatestNotification(cmd *m.GetLatestNotificationQuery) error {
 	return inTransaction(func(sess *DBSession) error {
 	return inTransaction(func(sess *DBSession) error {
 		notificationJournal := &m.NotificationJournal{}
 		notificationJournal := &m.NotificationJournal{}
-		_, err := sess.OrderBy("notification_journal.sent_at").Desc().Where("notification_journal.org_id = ? AND notification_journal.alert_id = ? AND notification_journal.notifier_id = ?", cmd.OrgId, cmd.AlertId, cmd.NotifierId).Get(notificationJournal)
+		_, err := sess.Desc("notification_journal.sent_at").Limit(1).Where("notification_journal.org_id = ? AND notification_journal.alert_id = ? AND notification_journal.notifier_id = ?", cmd.OrgId, cmd.AlertId, cmd.NotifierId).Get(notificationJournal)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}

+ 1 - 2
public/app/features/alerting/partials/notification_edit.html

@@ -20,8 +20,7 @@
       </div>
       </div>
       <div class="gf-form">
       <div class="gf-form">
         <a class="gf-form-label width-12" ng-click="ctrl.model.notifyOnce = !ctrl.model.notifyOnce;">{{ ctrl.model.notifyOnce ? 'Notify on state change' : 'Notify at most every' }}</a>
         <a class="gf-form-label width-12" ng-click="ctrl.model.notifyOnce = !ctrl.model.notifyOnce;">{{ ctrl.model.notifyOnce ? 'Notify on state change' : 'Notify at most every' }}</a>
-        <input class="gf-form-input max-width-10" type="number" required ng-model="ctrl.model.frequency" required ng-hide="ctrl.model.notifyOnce"></input>
-        <span class="gf-form-label max-width-5" ng-hide="ctrl.model.notifyOnce">seconds</span>
+        <input class="gf-form-input max-width-15" type="text" ng-model="ctrl.model.frequency" ng-if="!ctrl.model.notifyOnce"></input>
       </div>
       </div>
       <gf-form-switch
       <gf-form-switch
           class="gf-form"
           class="gf-form"