diff --git a/pkg/services/alerting/notifiers/pushover.go b/pkg/services/alerting/notifiers/pushover.go
index 55dc02c5f4a..6581328b745 100644
--- a/pkg/services/alerting/notifiers/pushover.go
+++ b/pkg/services/alerting/notifiers/pushover.go
@@ -1,8 +1,11 @@
package notifiers
import (
+ "bytes"
"fmt"
- "net/url"
+ "io"
+ "mime/multipart"
+ "os"
"strconv"
"github.com/grafana/grafana/pkg/bus"
@@ -91,6 +94,7 @@ func NewPushoverNotifier(model *m.AlertNotification) (alerting.Notifier, error)
retry, _ := strconv.Atoi(model.Settings.Get("retry").MustString())
expire, _ := strconv.Atoi(model.Settings.Get("expire").MustString())
sound := model.Settings.Get("sound").MustString()
+ uploadImage := model.Settings.Get("uploadImage").MustBool(true)
if userKey == "" {
return nil, alerting.ValidationError{Reason: "User key not given"}
@@ -107,6 +111,7 @@ func NewPushoverNotifier(model *m.AlertNotification) (alerting.Notifier, error)
Expire: expire,
Device: device,
Sound: sound,
+ Upload: uploadImage,
log: log.New("alerting.notifier.pushover"),
}, nil
}
@@ -120,6 +125,7 @@ type PushoverNotifier struct {
Expire int
Device string
Sound string
+ Upload bool
log log.Logger
}
@@ -140,38 +146,22 @@ func (this *PushoverNotifier) Notify(evalContext *alerting.EvalContext) error {
if evalContext.Error != nil {
message += fmt.Sprintf("\nError message: %s", evalContext.Error.Error())
}
- if evalContext.ImagePublicUrl != "" {
- message += fmt.Sprintf("\nShow graph image", evalContext.ImagePublicUrl)
- }
+
if message == "" {
message = "Notification message missing (Set a notification message to replace this text.)"
}
- q := url.Values{}
- q.Add("user", this.UserKey)
- q.Add("token", this.ApiToken)
- q.Add("priority", strconv.Itoa(this.Priority))
- if this.Priority == 2 {
- q.Add("retry", strconv.Itoa(this.Retry))
- q.Add("expire", strconv.Itoa(this.Expire))
+ headers, uploadBody, err := this.genPushoverBody(evalContext, message, ruleUrl)
+ if err != nil {
+ this.log.Error("Failed to generate body for pushover", "error", err)
+ return err
}
- if this.Device != "" {
- q.Add("device", this.Device)
- }
- if this.Sound != "default" {
- q.Add("sound", this.Sound)
- }
- q.Add("title", evalContext.GetNotificationTitle())
- q.Add("url", ruleUrl)
- q.Add("url_title", "Show dashboard with alert")
- q.Add("message", message)
- q.Add("html", "1")
cmd := &m.SendWebhookSync{
Url: PUSHOVER_ENDPOINT,
HttpMethod: "POST",
- HttpHeader: map[string]string{"Content-Type": "application/x-www-form-urlencoded"},
- Body: q.Encode(),
+ HttpHeader: headers,
+ Body: uploadBody.String(),
}
if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
@@ -181,3 +171,109 @@ func (this *PushoverNotifier) Notify(evalContext *alerting.EvalContext) error {
return nil
}
+
+func (this *PushoverNotifier) genPushoverBody(evalContext *alerting.EvalContext, message string, ruleUrl string) (map[string]string, bytes.Buffer, error) {
+ var b bytes.Buffer
+ var err error
+ w := multipart.NewWriter(&b)
+
+ // Add image only if requested and available
+ if this.Upload && evalContext.ImageOnDiskPath != "" {
+ f, err := os.Open(evalContext.ImageOnDiskPath)
+ if err != nil {
+ return nil, b, err
+ }
+ defer f.Close()
+
+ fw, err := w.CreateFormFile("attachment", evalContext.ImageOnDiskPath)
+ if err != nil {
+ return nil, b, err
+ }
+
+ _, err = io.Copy(fw, f)
+ if err != nil {
+ return nil, b, err
+ }
+ }
+
+ // Add the user token
+ err = w.WriteField("user", this.UserKey)
+ if err != nil {
+ return nil, b, err
+ }
+
+ // Add the api token
+ err = w.WriteField("token", this.ApiToken)
+ if err != nil {
+ return nil, b, err
+ }
+
+ // Add priority
+ err = w.WriteField("priority", strconv.Itoa(this.Priority))
+ if err != nil {
+ return nil, b, err
+ }
+
+ if this.Priority == 2 {
+ err = w.WriteField("retry", strconv.Itoa(this.Retry))
+ if err != nil {
+ return nil, b, err
+ }
+
+ err = w.WriteField("expire", strconv.Itoa(this.Expire))
+ if err != nil {
+ return nil, b, err
+ }
+ }
+
+ // Add device
+ if this.Device != "" {
+ err = w.WriteField("device", this.Device)
+ if err != nil {
+ return nil, b, err
+ }
+ }
+
+ // Add sound
+ if this.Sound != "default" {
+ err = w.WriteField("sound", this.Sound)
+ if err != nil {
+ return nil, b, err
+ }
+ }
+
+ // Add title
+ err = w.WriteField("title", evalContext.GetNotificationTitle())
+ if err != nil {
+ return nil, b, err
+ }
+
+ // Add URL
+ err = w.WriteField("url", ruleUrl)
+ if err != nil {
+ return nil, b, err
+ }
+ // Add URL title
+ err = w.WriteField("url_title", "Show dashboard with alert")
+ if err != nil {
+ return nil, b, err
+ }
+
+ // Add message
+ err = w.WriteField("message", message)
+ if err != nil {
+ return nil, b, err
+ }
+
+ // Mark as html message
+ err = w.WriteField("html", "1")
+ if err != nil {
+ return nil, b, err
+ }
+
+ w.Close()
+ headers := map[string]string{
+ "Content-Type": w.FormDataContentType(),
+ }
+ return headers, b, nil
+}