Sfoglia il codice sorgente

alerting: invert sendOnce to sendReminder

bergquist 7 anni fa
parent
commit
7333d7b8d4
28 ha cambiato i file con 173 aggiunte e 148 eliminazioni
  1. 23 23
      pkg/api/dtos/alerting.go
  2. 1 0
      pkg/api/dtos/alerting_test.go
  3. 23 23
      pkg/models/alert_notifications.go
  4. 1 1
      pkg/services/alerting/interfaces.go
  5. 1 1
      pkg/services/alerting/notifiers/alertmanager.go
  6. 28 26
      pkg/services/alerting/notifiers/base.go
  7. 10 3
      pkg/services/alerting/notifiers/base_test.go
  8. 1 1
      pkg/services/alerting/notifiers/dingding.go
  9. 1 1
      pkg/services/alerting/notifiers/discord.go
  10. 1 1
      pkg/services/alerting/notifiers/email.go
  11. 1 1
      pkg/services/alerting/notifiers/hipchat.go
  12. 1 1
      pkg/services/alerting/notifiers/kafka.go
  13. 1 1
      pkg/services/alerting/notifiers/line.go
  14. 1 1
      pkg/services/alerting/notifiers/opsgenie.go
  15. 1 1
      pkg/services/alerting/notifiers/pagerduty.go
  16. 1 1
      pkg/services/alerting/notifiers/pushover.go
  17. 1 1
      pkg/services/alerting/notifiers/sensu.go
  18. 1 1
      pkg/services/alerting/notifiers/slack.go
  19. 1 1
      pkg/services/alerting/notifiers/teams.go
  20. 1 1
      pkg/services/alerting/notifiers/telegram.go
  21. 1 1
      pkg/services/alerting/notifiers/threema.go
  22. 1 1
      pkg/services/alerting/notifiers/victorops.go
  23. 1 1
      pkg/services/alerting/notifiers/webhook.go
  24. 16 16
      pkg/services/sqlstore/alert_notification.go
  25. 32 31
      pkg/services/sqlstore/alert_notification_test.go
  26. 3 2
      pkg/services/sqlstore/migrations/alert_mig.go
  27. 1 1
      public/app/features/alerting/notification_edit_ctrl.ts
  28. 18 5
      public/app/features/alerting/partials/notification_edit.html

+ 23 - 23
pkg/api/dtos/alerting.go

@@ -49,28 +49,28 @@ func formatShort(interval time.Duration) string {
 
 func NewAlertNotification(notification *models.AlertNotification) *AlertNotification {
 	return &AlertNotification{
-		Id:         notification.Id,
-		Name:       notification.Name,
-		Type:       notification.Type,
-		IsDefault:  notification.IsDefault,
-		Created:    notification.Created,
-		Updated:    notification.Updated,
-		Frequency:  formatShort(notification.Frequency),
-		NotifyOnce: notification.NotifyOnce,
-		Settings:   notification.Settings,
+		Id:           notification.Id,
+		Name:         notification.Name,
+		Type:         notification.Type,
+		IsDefault:    notification.IsDefault,
+		Created:      notification.Created,
+		Updated:      notification.Updated,
+		Frequency:    formatShort(notification.Frequency),
+		SendReminder: notification.SendReminder,
+		Settings:     notification.Settings,
 	}
 }
 
 type AlertNotification struct {
-	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"`
+	Id           int64            `json:"id"`
+	Name         string           `json:"name"`
+	Type         string           `json:"type"`
+	IsDefault    bool             `json:"isDefault"`
+	SendReminder bool             `json:"sendReminder"`
+	Frequency    string           `json:"frequency"`
+	Created      time.Time        `json:"created"`
+	Updated      time.Time        `json:"updated"`
+	Settings     *simplejson.Json `json:"settings"`
 }
 
 type AlertTestCommand struct {
@@ -100,11 +100,11 @@ type EvalMatch struct {
 }
 
 type NotificationTestCommand struct {
-	Name       string           `json:"name"`
-	Type       string           `json:"type"`
-	NotifyOnce bool             `json:"notifyOnce"`
-	Frequency  string           `json:"frequency"`
-	Settings   *simplejson.Json `json:"settings"`
+	Name         string           `json:"name"`
+	Type         string           `json:"type"`
+	SendReminder bool             `json:"sendReminder"`
+	Frequency    string           `json:"frequency"`
+	Settings     *simplejson.Json `json:"settings"`
 }
 
 type PauseAlertCommand struct {

+ 1 - 0
pkg/api/dtos/alerting_test.go

@@ -14,6 +14,7 @@ func TestFormatShort(t *testing.T) {
 		{interval: time.Duration(time.Hour + time.Minute), expected: "1h1m"},
 		{interval: time.Duration((time.Hour * 10) + time.Minute), expected: "10h1m"},
 		{interval: time.Duration((time.Hour * 10) + (time.Minute * 10) + time.Second), expected: "10h10m1s"},
+		{interval: time.Duration(time.Minute * 10), expected: "10m"},
 	}
 
 	for _, tc := range tcs {

+ 23 - 23
pkg/models/alert_notifications.go

@@ -12,38 +12,38 @@ var (
 )
 
 type AlertNotification struct {
-	Id         int64            `json:"id"`
-	OrgId      int64            `json:"-"`
-	Name       string           `json:"name"`
-	Type       string           `json:"type"`
-	NotifyOnce bool             `json:"notifyOnce"`
-	Frequency  time.Duration    `json:"frequency"`
-	IsDefault  bool             `json:"isDefault"`
-	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"`
+	SendReminder bool             `json:"sendReminder"`
+	Frequency    time.Duration    `json:"frequency"`
+	IsDefault    bool             `json:"isDefault"`
+	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"`
-	NotifyOnce bool             `json:"notifyOnce"`
-	Frequency  string           `json:"frequency"`
-	IsDefault  bool             `json:"isDefault"`
-	Settings   *simplejson.Json `json:"settings"`
+	Name         string           `json:"name"  binding:"Required"`
+	Type         string           `json:"type"  binding:"Required"`
+	SendReminder bool             `json:"sendReminder"`
+	Frequency    string           `json:"frequency"`
+	IsDefault    bool             `json:"isDefault"`
+	Settings     *simplejson.Json `json:"settings"`
 
 	OrgId  int64 `json:"-"`
 	Result *AlertNotification
 }
 
 type UpdateAlertNotificationCommand struct {
-	Id         int64            `json:"id"  binding:"Required"`
-	Name       string           `json:"name"  binding:"Required"`
-	Type       string           `json:"type"  binding:"Required"`
-	NotifyOnce bool             `json:"notifyOnce"`
-	Frequency  string           `json:"frequency"`
-	IsDefault  bool             `json:"isDefault"`
-	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"`
+	SendReminder bool             `json:"sendReminder"`
+	Frequency    string           `json:"frequency"`
+	IsDefault    bool             `json:"isDefault"`
+	Settings     *simplejson.Json `json:"settings"  binding:"Required"`
 
 	OrgId  int64 `json:"-"`
 	Result *AlertNotification

+ 1 - 1
pkg/services/alerting/interfaces.go

@@ -19,7 +19,7 @@ type Notifier interface {
 
 	GetNotifierId() int64
 	GetIsDefault() bool
-	GetNotifyOnce() bool
+	GetSendReminder() bool
 	GetFrequency() time.Duration
 }
 

+ 1 - 1
pkg/services/alerting/notifiers/alertmanager.go

@@ -33,7 +33,7 @@ func NewAlertmanagerNotifier(model *m.AlertNotification) (alerting.Notifier, err
 	}
 
 	return &AlertmanagerNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		Url:          url,
 		log:          log.New("alerting.notifier.prometheus-alertmanager"),
 	}, nil

+ 28 - 26
pkg/services/alerting/notifiers/base.go

@@ -3,54 +3,56 @@ package notifiers
 import (
 	"time"
 
-	"github.com/grafana/grafana/pkg/components/simplejson"
-	m "github.com/grafana/grafana/pkg/models"
+	"github.com/grafana/grafana/pkg/models"
 	"github.com/grafana/grafana/pkg/services/alerting"
 )
 
 type NotifierBase struct {
-	Name        string
-	Type        string
-	Id          int64
-	IsDeault    bool
-	UploadImage bool
-	NotifyOnce  bool
-	Frequency   time.Duration
+	Name         string
+	Type         string
+	Id           int64
+	IsDeault     bool
+	UploadImage  bool
+	SendReminder bool
+	Frequency    time.Duration
 }
 
-func NewNotifierBase(id int64, isDefault bool, name, notifierType string, notifyOnce bool, frequency time.Duration, model *simplejson.Json) NotifierBase {
+func NewNotifierBase(model *models.AlertNotification) NotifierBase {
 	uploadImage := true
-	value, exist := model.CheckGet("uploadImage")
+	value, exist := model.Settings.CheckGet("uploadImage")
 	if exist {
 		uploadImage = value.MustBool()
 	}
 
 	return NotifierBase{
-		Id:          id,
-		Name:        name,
-		IsDeault:    isDefault,
-		Type:        notifierType,
-		UploadImage: uploadImage,
-		NotifyOnce:  notifyOnce,
-		Frequency:   frequency,
+		Id:           model.Id,
+		Name:         model.Name,
+		IsDeault:     model.IsDefault,
+		Type:         model.Type,
+		UploadImage:  uploadImage,
+		SendReminder: model.SendReminder,
+		Frequency:    model.Frequency,
 	}
 }
 
-func defaultShouldNotify(context *alerting.EvalContext, notifyOnce bool, frequency time.Duration, lastNotify *time.Time) bool {
+func defaultShouldNotify(context *alerting.EvalContext, sendReminder bool, frequency time.Duration, lastNotify *time.Time) bool {
 	// Only notify on state change.
-	if context.PrevAlertState == context.Rule.State && notifyOnce {
+	if context.PrevAlertState == context.Rule.State && !sendReminder {
 		return false
 	}
+
 	// Do not notify if interval has not elapsed
-	if !notifyOnce && lastNotify != nil && lastNotify.Add(frequency).After(time.Now()) {
+	if sendReminder && lastNotify != nil && lastNotify.Add(frequency).After(time.Now()) {
 		return false
 	}
+
 	// Do not notify if alert state if OK or pending even on repeated notify
-	if !notifyOnce && (context.Rule.State == m.AlertStateOK || context.Rule.State == m.AlertStatePending) {
+	if sendReminder && (context.Rule.State == models.AlertStateOK || context.Rule.State == models.AlertStatePending) {
 		return false
 	}
+
 	// Do not notify when we become OK for the first time.
-	if (context.PrevAlertState == m.AlertStatePending) && (context.Rule.State == m.AlertStateOK) {
+	if (context.PrevAlertState == models.AlertStatePending) && (context.Rule.State == models.AlertStateOK) {
 		return false
 	}
 	return true
@@ -58,7 +60,7 @@ func defaultShouldNotify(context *alerting.EvalContext, notifyOnce bool, frequen
 
 func (n *NotifierBase) ShouldNotify(context *alerting.EvalContext) bool {
 	lastNotify := context.LastNotify(n.Id)
-	return defaultShouldNotify(context, n.NotifyOnce, n.Frequency, lastNotify)
+	return defaultShouldNotify(context, n.SendReminder, n.Frequency, lastNotify)
 }
 
 func (n *NotifierBase) GetType() string {
@@ -77,8 +79,8 @@ func (n *NotifierBase) GetIsDefault() bool {
 	return n.IsDeault
 }
 
-func (n *NotifierBase) GetNotifyOnce() bool {
-	return n.NotifyOnce
+func (n *NotifierBase) GetSendReminder() bool {
+	return n.SendReminder
 }
 
 func (n *NotifierBase) GetFrequency() time.Duration {

+ 10 - 3
pkg/services/alerting/notifiers/base_test.go

@@ -16,22 +16,29 @@ func TestBaseNotifier(t *testing.T) {
 		Convey("default constructor for notifiers", func() {
 			bJson := simplejson.New()
 
+			model := &m.AlertNotification{
+				Id:       1,
+				Name:     "name",
+				Type:     "email",
+				Settings: bJson,
+			}
+
 			Convey("can parse false value", func() {
 				bJson.Set("uploadImage", false)
 
-				base := NewNotifierBase(1, false, "name", "email", true, 0, bJson)
+				base := NewNotifierBase(model)
 				So(base.UploadImage, ShouldBeFalse)
 			})
 
 			Convey("can parse true value", func() {
 				bJson.Set("uploadImage", true)
 
-				base := NewNotifierBase(1, false, "name", "email", true, 0, bJson)
+				base := NewNotifierBase(model)
 				So(base.UploadImage, ShouldBeTrue)
 			})
 
 			Convey("default value should be true for backwards compatibility", func() {
-				base := NewNotifierBase(1, false, "name", "email", true, 0, bJson)
+				base := NewNotifierBase(model)
 				So(base.UploadImage, ShouldBeTrue)
 			})
 		})

+ 1 - 1
pkg/services/alerting/notifiers/dingding.go

@@ -32,7 +32,7 @@ func NewDingDingNotifier(model *m.AlertNotification) (alerting.Notifier, error)
 	}
 
 	return &DingDingNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		Url:          url,
 		log:          log.New("alerting.notifier.dingding"),
 	}, nil

+ 1 - 1
pkg/services/alerting/notifiers/discord.go

@@ -39,7 +39,7 @@ func NewDiscordNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
 	}
 
 	return &DiscordNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		WebhookURL:   url,
 		log:          log.New("alerting.notifier.discord"),
 	}, nil

+ 1 - 1
pkg/services/alerting/notifiers/email.go

@@ -52,7 +52,7 @@ func NewEmailNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
 	})
 
 	return &EmailNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		Addresses:    addresses,
 		log:          log.New("alerting.notifier.email"),
 	}, nil

+ 1 - 1
pkg/services/alerting/notifiers/hipchat.go

@@ -59,7 +59,7 @@ func NewHipChatNotifier(model *models.AlertNotification) (alerting.Notifier, err
 	roomId := model.Settings.Get("roomid").MustString()
 
 	return &HipChatNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		Url:          url,
 		ApiKey:       apikey,
 		RoomId:       roomId,

+ 1 - 1
pkg/services/alerting/notifiers/kafka.go

@@ -43,7 +43,7 @@ func NewKafkaNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
 	}
 
 	return &KafkaNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		Endpoint:     endpoint,
 		Topic:        topic,
 		log:          log.New("alerting.notifier.kafka"),

+ 1 - 1
pkg/services/alerting/notifiers/line.go

@@ -39,7 +39,7 @@ func NewLINENotifier(model *m.AlertNotification) (alerting.Notifier, error) {
 	}
 
 	return &LineNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		Token:        token,
 		log:          log.New("alerting.notifier.line"),
 	}, nil

+ 1 - 1
pkg/services/alerting/notifiers/opsgenie.go

@@ -56,7 +56,7 @@ func NewOpsGenieNotifier(model *m.AlertNotification) (alerting.Notifier, error)
 	}
 
 	return &OpsGenieNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		ApiKey:       apiKey,
 		ApiUrl:       apiUrl,
 		AutoClose:    autoClose,

+ 1 - 1
pkg/services/alerting/notifiers/pagerduty.go

@@ -51,7 +51,7 @@ func NewPagerdutyNotifier(model *m.AlertNotification) (alerting.Notifier, error)
 	}
 
 	return &PagerdutyNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		Key:          key,
 		AutoResolve:  autoResolve,
 		log:          log.New("alerting.notifier.pagerduty"),

+ 1 - 1
pkg/services/alerting/notifiers/pushover.go

@@ -99,7 +99,7 @@ func NewPushoverNotifier(model *m.AlertNotification) (alerting.Notifier, error)
 		return nil, alerting.ValidationError{Reason: "API token not given"}
 	}
 	return &PushoverNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		UserKey:      userKey,
 		ApiToken:     apiToken,
 		Priority:     priority,

+ 1 - 1
pkg/services/alerting/notifiers/sensu.go

@@ -51,7 +51,7 @@ func NewSensuNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
 	}
 
 	return &SensuNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		Url:          url,
 		User:         model.Settings.Get("username").MustString(),
 		Source:       model.Settings.Get("source").MustString(),

+ 1 - 1
pkg/services/alerting/notifiers/slack.go

@@ -78,7 +78,7 @@ func NewSlackNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
 	uploadImage := model.Settings.Get("uploadImage").MustBool(true)
 
 	return &SlackNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		Url:          url,
 		Recipient:    recipient,
 		Mention:      mention,

+ 1 - 1
pkg/services/alerting/notifiers/teams.go

@@ -33,7 +33,7 @@ func NewTeamsNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
 	}
 
 	return &TeamsNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		Url:          url,
 		log:          log.New("alerting.notifier.teams"),
 	}, nil

+ 1 - 1
pkg/services/alerting/notifiers/telegram.go

@@ -78,7 +78,7 @@ func NewTelegramNotifier(model *m.AlertNotification) (alerting.Notifier, error)
 	}
 
 	return &TelegramNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		BotToken:     botToken,
 		ChatID:       chatId,
 		UploadImage:  uploadImage,

+ 1 - 1
pkg/services/alerting/notifiers/threema.go

@@ -106,7 +106,7 @@ func NewThreemaNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
 	}
 
 	return &ThreemaNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		GatewayID:    gatewayID,
 		RecipientID:  recipientID,
 		APISecret:    apiSecret,

+ 1 - 1
pkg/services/alerting/notifiers/victorops.go

@@ -51,7 +51,7 @@ func NewVictoropsNotifier(model *models.AlertNotification) (alerting.Notifier, e
 	}
 
 	return &VictoropsNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		URL:          url,
 		AutoResolve:  autoResolve,
 		log:          log.New("alerting.notifier.victorops"),

+ 1 - 1
pkg/services/alerting/notifiers/webhook.go

@@ -47,7 +47,7 @@ func NewWebHookNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
 	}
 
 	return &WebhookNotifier{
-		NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.NotifyOnce, model.Frequency, model.Settings),
+		NotifierBase: NewNotifierBase(model),
 		Url:          url,
 		User:         model.Settings.Get("username").MustString(),
 		Password:     model.Settings.Get("password").MustString(),

+ 16 - 16
pkg/services/sqlstore/alert_notification.go

@@ -57,7 +57,7 @@ func GetAlertNotificationsToSend(query *m.GetAlertNotificationsToSendQuery) erro
 										alert_notification.updated,
 										alert_notification.settings,
 										alert_notification.is_default,
-										alert_notification.notify_once,
+										alert_notification.send_reminder,
 										alert_notification.frequency
 										FROM alert_notification
 	  							`)
@@ -97,7 +97,7 @@ func getAlertNotificationInternal(query *m.GetAlertNotificationsQuery, sess *DBS
 										alert_notification.updated,
 										alert_notification.settings,
 										alert_notification.is_default,
-										alert_notification.notify_once,
+										alert_notification.send_reminder,
 										alert_notification.frequency
 										FROM alert_notification
 	  							`)
@@ -145,7 +145,7 @@ func CreateAlertNotificationCommand(cmd *m.CreateAlertNotificationCommand) error
 		}
 
 		var frequency time.Duration
-		if !cmd.NotifyOnce {
+		if cmd.SendReminder {
 			if cmd.Frequency == "" {
 				return m.ErrNotificationFrequencyNotFound
 			}
@@ -157,18 +157,18 @@ func CreateAlertNotificationCommand(cmd *m.CreateAlertNotificationCommand) error
 		}
 
 		alertNotification := &m.AlertNotification{
-			OrgId:      cmd.OrgId,
-			Name:       cmd.Name,
-			Type:       cmd.Type,
-			Settings:   cmd.Settings,
-			NotifyOnce: cmd.NotifyOnce,
-			Frequency:  frequency,
-			Created:    time.Now(),
-			Updated:    time.Now(),
-			IsDefault:  cmd.IsDefault,
+			OrgId:        cmd.OrgId,
+			Name:         cmd.Name,
+			Type:         cmd.Type,
+			Settings:     cmd.Settings,
+			SendReminder: cmd.SendReminder,
+			Frequency:    frequency,
+			Created:      time.Now(),
+			Updated:      time.Now(),
+			IsDefault:    cmd.IsDefault,
 		}
 
-		if _, err = sess.MustCols("notify_once").Insert(alertNotification); err != nil {
+		if _, err = sess.MustCols("send_reminder").Insert(alertNotification); err != nil {
 			return err
 		}
 
@@ -200,9 +200,9 @@ func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error {
 		current.Name = cmd.Name
 		current.Type = cmd.Type
 		current.IsDefault = cmd.IsDefault
-		current.NotifyOnce = cmd.NotifyOnce
+		current.SendReminder = cmd.SendReminder
 
-		if !current.NotifyOnce {
+		if current.SendReminder {
 			if cmd.Frequency == "" {
 				return m.ErrNotificationFrequencyNotFound
 			}
@@ -215,7 +215,7 @@ func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error {
 			current.Frequency = frequency
 		}
 
-		sess.UseBool("is_default", "notify_once")
+		sess.UseBool("is_default", "send_reminder")
 
 		if affected, err := sess.ID(cmd.Id).Update(current); err != nil {
 			return err

+ 32 - 31
pkg/services/sqlstore/alert_notification_test.go

@@ -23,13 +23,13 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
 			So(cmd.Result, ShouldBeNil)
 		})
 
-		Convey("Cannot save alert notifier with notitfyonce = false", func() {
+		Convey("Cannot save alert notifier with send reminder = true", func() {
 			cmd := &m.CreateAlertNotificationCommand{
-				Name:       "ops",
-				Type:       "email",
-				OrgId:      1,
-				NotifyOnce: false,
-				Settings:   simplejson.New(),
+				Name:         "ops",
+				Type:         "email",
+				OrgId:        1,
+				SendReminder: true,
+				Settings:     simplejson.New(),
 			}
 
 			Convey("and missing frequency", func() {
@@ -47,19 +47,19 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
 
 		Convey("Cannot update alert notifier with notitfyonce = false", func() {
 			cmd := &m.CreateAlertNotificationCommand{
-				Name:       "ops update",
-				Type:       "email",
-				OrgId:      1,
-				NotifyOnce: true,
-				Settings:   simplejson.New(),
+				Name:         "ops update",
+				Type:         "email",
+				OrgId:        1,
+				SendReminder: false,
+				Settings:     simplejson.New(),
 			}
 
 			err := CreateAlertNotificationCommand(cmd)
 			So(err, ShouldBeNil)
 
 			updateCmd := &m.UpdateAlertNotificationCommand{
-				Id:         cmd.Result.Id,
-				NotifyOnce: false,
+				Id:           cmd.Result.Id,
+				SendReminder: true,
 			}
 
 			Convey("and missing frequency", func() {
@@ -71,18 +71,19 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
 				updateCmd.Frequency = "invalid duration"
 
 				err := UpdateAlertNotification(updateCmd)
+				So(err, ShouldNotBeNil)
 				So(err.Error(), ShouldEqual, "time: invalid duration invalid duration")
 			})
 		})
 
 		Convey("Can save Alert Notification", func() {
 			cmd := &m.CreateAlertNotificationCommand{
-				Name:       "ops",
-				Type:       "email",
-				OrgId:      1,
-				NotifyOnce: true,
-				Frequency:  "10s",
-				Settings:   simplejson.New(),
+				Name:         "ops",
+				Type:         "email",
+				OrgId:        1,
+				SendReminder: true,
+				Frequency:    "10s",
+				Settings:     simplejson.New(),
 			}
 
 			err := CreateAlertNotificationCommand(cmd)
@@ -98,13 +99,13 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
 
 			Convey("Can update alert notification", func() {
 				newCmd := &m.UpdateAlertNotificationCommand{
-					Name:       "NewName",
-					Type:       "webhook",
-					OrgId:      cmd.Result.OrgId,
-					NotifyOnce: true,
-					Frequency:  "10s",
-					Settings:   simplejson.New(),
-					Id:         cmd.Result.Id,
+					Name:         "NewName",
+					Type:         "webhook",
+					OrgId:        cmd.Result.OrgId,
+					SendReminder: true,
+					Frequency:    "10s",
+					Settings:     simplejson.New(),
+					Id:           cmd.Result.Id,
 				}
 				err := UpdateAlertNotification(newCmd)
 				So(err, ShouldBeNil)
@@ -113,12 +114,12 @@ func TestAlertNotificationSQLAccess(t *testing.T) {
 		})
 
 		Convey("Can search using an array of ids", func() {
-			cmd1 := m.CreateAlertNotificationCommand{Name: "nagios", Type: "webhook", OrgId: 1, NotifyOnce: true, Frequency: "10s", Settings: simplejson.New()}
-			cmd2 := m.CreateAlertNotificationCommand{Name: "slack", Type: "webhook", OrgId: 1, NotifyOnce: true, Frequency: "10s", Settings: simplejson.New()}
-			cmd3 := m.CreateAlertNotificationCommand{Name: "ops2", Type: "email", OrgId: 1, NotifyOnce: true, Frequency: "10s", Settings: simplejson.New()}
-			cmd4 := m.CreateAlertNotificationCommand{IsDefault: true, Name: "default", Type: "email", OrgId: 1, NotifyOnce: true, Frequency: "10s", Settings: simplejson.New()}
+			cmd1 := m.CreateAlertNotificationCommand{Name: "nagios", Type: "webhook", OrgId: 1, SendReminder: true, Frequency: "10s", Settings: simplejson.New()}
+			cmd2 := m.CreateAlertNotificationCommand{Name: "slack", Type: "webhook", OrgId: 1, SendReminder: true, Frequency: "10s", Settings: simplejson.New()}
+			cmd3 := m.CreateAlertNotificationCommand{Name: "ops2", Type: "email", OrgId: 1, SendReminder: true, Frequency: "10s", Settings: simplejson.New()}
+			cmd4 := m.CreateAlertNotificationCommand{IsDefault: true, Name: "default", Type: "email", OrgId: 1, SendReminder: true, Frequency: "10s", Settings: simplejson.New()}
 
-			otherOrg := m.CreateAlertNotificationCommand{Name: "default", Type: "email", OrgId: 2, NotifyOnce: true, Frequency: "10s", Settings: simplejson.New()}
+			otherOrg := m.CreateAlertNotificationCommand{Name: "default", Type: "email", OrgId: 2, SendReminder: true, Frequency: "10s", Settings: simplejson.New()}
 
 			So(CreateAlertNotificationCommand(&cmd1), ShouldBeNil)
 			So(CreateAlertNotificationCommand(&cmd2), ShouldBeNil)

+ 3 - 2
pkg/services/sqlstore/migrations/alert_mig.go

@@ -68,9 +68,10 @@ func addAlertMigrations(mg *Migrator) {
 	mg.AddMigration("Add column frequency", NewAddColumnMigration(alert_notification, &Column{
 		Name: "frequency", Type: DB_BigInt, Nullable: true,
 	}))
-	mg.AddMigration("Add column notify_once", NewAddColumnMigration(alert_notification, &Column{
-		Name: "notify_once", Type: DB_Bool, Nullable: false, Default: "1",
+	mg.AddMigration("Add column send_reminder", NewAddColumnMigration(alert_notification, &Column{
+		Name: "send_reminder", Type: DB_Bool, Nullable: true, Default: "0",
 	}))
+
 	mg.AddMigration("add index alert_notification org_id & name", NewAddIndexMigration(alert_notification, alert_notification.Indices[0]))
 
 	notification_journal := Table{

+ 1 - 1
public/app/features/alerting/notification_edit_ctrl.ts

@@ -11,7 +11,7 @@ export class AlertNotificationEditCtrl {
   model: any;
   defaults: any = {
     type: 'email',
-    notifyOnce: true,
+    sendReminder: false,
     frequency: '15m',
     settings: {
       httpMethod: 'POST',

+ 18 - 5
public/app/features/alerting/partials/notification_edit.html

@@ -34,14 +34,27 @@
       </gf-form-switch>
       <gf-form-switch
           class="gf-form"
-          label="Notify once"
+          label="Send reminder"
           label-class="width-12"
-          checked="ctrl.model.notifyOnce"
+          checked="ctrl.model.sendReminder"
           tooltip="Choose to either notify on state change or at every interval">
       </gf-form-switch>
-      <div class="gf-form">
-        <span class="gf-form-label width-12" ng-if="!ctrl.model.notifyOnce">Notify every</span>
-        <input class="gf-form-input max-width-15" type="text" required ng-model="ctrl.model.frequency" required ng-if="!ctrl.model.notifyOnce"></input>
+      <div class="gf-form-inline">
+        <div class="gf-form">
+          <span class="gf-form-label width-12" ng-if="ctrl.model.sendReminder">Send reminder every</span>
+          <input
+            class="gf-form-input max-width-15"
+            type="text"
+            ng-model="ctrl.model.frequency"
+            ng-required="ctrl.model.sendReminder"
+            ng-if="ctrl.model.sendReminder"
+            spellcheck='false'
+            placeholder='15m'></input>
+          <info-popover mode="right-absolute">
+            Specify at what interval you want reminder's about this alerting beeing triggered.
+            Ex. 60s, 10m, 30m, 1h
+          </info-popover>
+        </div>
       </div>
     </div>