Pushover alert, support for different sound for OK (#16525)

Closes #15889
This commit is contained in:
Hofls 2019-04-12 17:57:17 +05:00 committed by Carl Bergquist
parent e8d6995737
commit c17226af95
2 changed files with 103 additions and 48 deletions

View File

@ -17,6 +17,31 @@ import (
const PUSHOVER_ENDPOINT = "https://api.pushover.net/1/messages.json" const PUSHOVER_ENDPOINT = "https://api.pushover.net/1/messages.json"
func init() { func init() {
sounds := `
'default',
'pushover',
'bike',
'bugle',
'cashregister',
'classical',
'cosmic',
'falling',
'gamelan',
'incoming',
'intermission',
'magic',
'mechanical',
'pianobar',
'siren',
'spacealarm',
'tugboat',
'alien',
'climb',
'persistent',
'echo',
'updown',
'none'`
alerting.RegisterNotifier(&alerting.NotifierPlugin{ alerting.RegisterNotifier(&alerting.NotifierPlugin{
Type: "pushover", Type: "pushover",
Name: "Pushover", Name: "Pushover",
@ -55,33 +80,17 @@ func init() {
<input type="text" class="gf-form-input max-width-14" ng-required="ctrl.model.settings.priority == '2'" placeholder="maximum 86400 seconds" ng-model="ctrl.model.settings.expire" ng-init="ctrl.model.settings.expire=ctrl.model.settings.expire||'3600'"></input> <input type="text" class="gf-form-input max-width-14" ng-required="ctrl.model.settings.priority == '2'" placeholder="maximum 86400 seconds" ng-model="ctrl.model.settings.expire" ng-init="ctrl.model.settings.expire=ctrl.model.settings.expire||'3600'"></input>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-10">Sound</span> <span class="gf-form-label width-10">Alerting sound</span>
<select class="gf-form-input max-width-14" ng-model="ctrl.model.settings.sound" ng-options="s for s in [ <select class="gf-form-input max-width-14" ng-model="ctrl.model.settings.sound" ng-options="s for s in [
'default', ` + sounds + `
'pushover',
'bike',
'bugle',
'cashregister',
'classical',
'cosmic',
'falling',
'gamelan',
'incoming',
'intermission',
'magic',
'mechanical',
'pianobar',
'siren',
'spacealarm',
'tugboat',
'alien',
'climb',
'persistent',
'echo',
'updown',
'none'
]" ng-init="ctrl.model.settings.sound=ctrl.model.settings.sound||'default'"></select> ]" ng-init="ctrl.model.settings.sound=ctrl.model.settings.sound||'default'"></select>
</div> </div>
<div class="gf-form">
<span class="gf-form-label width-10">OK sound</span>
<select class="gf-form-input max-width-14" ng-model="ctrl.model.settings.okSound" ng-options="s for s in [
` + sounds + `
]" ng-init="ctrl.model.settings.okSound=ctrl.model.settings.okSound||'default'"></select>
</div>
`, `,
}) })
} }
@ -93,7 +102,8 @@ func NewPushoverNotifier(model *m.AlertNotification) (alerting.Notifier, error)
priority, _ := strconv.Atoi(model.Settings.Get("priority").MustString()) priority, _ := strconv.Atoi(model.Settings.Get("priority").MustString())
retry, _ := strconv.Atoi(model.Settings.Get("retry").MustString()) retry, _ := strconv.Atoi(model.Settings.Get("retry").MustString())
expire, _ := strconv.Atoi(model.Settings.Get("expire").MustString()) expire, _ := strconv.Atoi(model.Settings.Get("expire").MustString())
sound := model.Settings.Get("sound").MustString() alertingSound := model.Settings.Get("sound").MustString()
okSound := model.Settings.Get("okSound").MustString()
uploadImage := model.Settings.Get("uploadImage").MustBool(true) uploadImage := model.Settings.Get("uploadImage").MustBool(true)
if userKey == "" { if userKey == "" {
@ -103,30 +113,32 @@ func NewPushoverNotifier(model *m.AlertNotification) (alerting.Notifier, error)
return nil, alerting.ValidationError{Reason: "API token not given"} return nil, alerting.ValidationError{Reason: "API token not given"}
} }
return &PushoverNotifier{ return &PushoverNotifier{
NotifierBase: NewNotifierBase(model), NotifierBase: NewNotifierBase(model),
UserKey: userKey, UserKey: userKey,
ApiToken: apiToken, ApiToken: apiToken,
Priority: priority, Priority: priority,
Retry: retry, Retry: retry,
Expire: expire, Expire: expire,
Device: device, Device: device,
Sound: sound, AlertingSound: alertingSound,
Upload: uploadImage, OkSound: okSound,
log: log.New("alerting.notifier.pushover"), Upload: uploadImage,
log: log.New("alerting.notifier.pushover"),
}, nil }, nil
} }
type PushoverNotifier struct { type PushoverNotifier struct {
NotifierBase NotifierBase
UserKey string UserKey string
ApiToken string ApiToken string
Priority int Priority int
Retry int Retry int
Expire int Expire int
Device string Device string
Sound string AlertingSound string
Upload bool OkSound string
log log.Logger Upload bool
log log.Logger
} }
func (this *PushoverNotifier) Notify(evalContext *alerting.EvalContext) error { func (this *PushoverNotifier) Notify(evalContext *alerting.EvalContext) error {
@ -235,8 +247,12 @@ func (this *PushoverNotifier) genPushoverBody(evalContext *alerting.EvalContext,
} }
// Add sound // Add sound
if this.Sound != "default" { sound := this.AlertingSound
err = w.WriteField("sound", this.Sound) if evalContext.Rule.State == m.AlertStateOK {
sound = this.OkSound
}
if sound != "default" {
err = w.WriteField("sound", sound)
if err != nil { if err != nil {
return nil, b, err return nil, b, err
} }

View File

@ -1,6 +1,9 @@
package notifiers package notifiers
import ( import (
"context"
"github.com/grafana/grafana/pkg/services/alerting"
"strings"
"testing" "testing"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
@ -32,7 +35,8 @@ func TestPushoverNotifier(t *testing.T) {
"apiToken": "4SrUFQL4A5V5TQ1z5Pg9nxHXPXSTve", "apiToken": "4SrUFQL4A5V5TQ1z5Pg9nxHXPXSTve",
"userKey": "tzNZYf36y0ohWwXo4XoUrB61rz1A4o", "userKey": "tzNZYf36y0ohWwXo4XoUrB61rz1A4o",
"priority": "1", "priority": "1",
"sound": "pushover" "sound": "pushover",
"okSound": "magic"
}` }`
settingsJSON, _ := simplejson.NewJson([]byte(json)) settingsJSON, _ := simplejson.NewJson([]byte(json))
@ -51,8 +55,43 @@ func TestPushoverNotifier(t *testing.T) {
So(pushoverNotifier.ApiToken, ShouldEqual, "4SrUFQL4A5V5TQ1z5Pg9nxHXPXSTve") So(pushoverNotifier.ApiToken, ShouldEqual, "4SrUFQL4A5V5TQ1z5Pg9nxHXPXSTve")
So(pushoverNotifier.UserKey, ShouldEqual, "tzNZYf36y0ohWwXo4XoUrB61rz1A4o") So(pushoverNotifier.UserKey, ShouldEqual, "tzNZYf36y0ohWwXo4XoUrB61rz1A4o")
So(pushoverNotifier.Priority, ShouldEqual, 1) So(pushoverNotifier.Priority, ShouldEqual, 1)
So(pushoverNotifier.Sound, ShouldEqual, "pushover") So(pushoverNotifier.AlertingSound, ShouldEqual, "pushover")
So(pushoverNotifier.OkSound, ShouldEqual, "magic")
}) })
}) })
}) })
} }
func TestGenPushoverBody(t *testing.T) {
Convey("Pushover body generation tests", t, func() {
Convey("Given common sounds", func() {
sirenSound := "siren_sound_tst"
successSound := "success_sound_tst"
notifier := &PushoverNotifier{AlertingSound: sirenSound, OkSound: successSound}
Convey("When alert is firing - should use siren sound", func() {
evalContext := alerting.NewEvalContext(context.Background(),
&alerting.Rule{
State: m.AlertStateAlerting,
})
_, pushoverBody, err := notifier.genPushoverBody(evalContext, "", "")
So(err, ShouldBeNil)
So(strings.Contains(pushoverBody.String(), sirenSound), ShouldBeTrue)
})
Convey("When alert is ok - should use success sound", func() {
evalContext := alerting.NewEvalContext(context.Background(),
&alerting.Rule{
State: m.AlertStateOK,
})
_, pushoverBody, err := notifier.genPushoverBody(evalContext, "", "")
So(err, ShouldBeNil)
So(strings.Contains(pushoverBody.String(), successSound), ShouldBeTrue)
})
})
})
}