From 67046c5e796dbcfae71b2eaa8c90c8241d6801ac Mon Sep 17 00:00:00 2001 From: George Robinson Date: Mon, 20 Jun 2022 15:45:35 +0100 Subject: [PATCH] Alerting: Add support for images in Threema alerts (#50734) --- .../ngalert/notifier/channels/testing.go | 6 +++--- .../ngalert/notifier/channels/threema.go | 17 +++++++++++++++-- .../ngalert/notifier/channels/threema_test.go | 18 ++++++++++-------- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/pkg/services/ngalert/notifier/channels/testing.go b/pkg/services/ngalert/notifier/channels/testing.go index bf2e23b1108..af7467cc62e 100644 --- a/pkg/services/ngalert/notifier/channels/testing.go +++ b/pkg/services/ngalert/notifier/channels/testing.go @@ -30,10 +30,10 @@ func (f *fakeImageStore) GetImage(_ context.Context, token string) (*ngmodels.Im // Each image has a token and a URL, but does not have a file on disk. func newFakeImageStore(n int) ImageStore { s := fakeImageStore{} - for i := 0; i < n; i++ { + for i := 1; i <= n; i++ { s.Images = append(s.Images, &ngmodels.Image{ Token: fmt.Sprintf("test-image-%d", i), - URL: fmt.Sprintf("https://www.example.com/test-image-%d.jpg", 1), + URL: fmt.Sprintf("https://www.example.com/test-image-%d.jpg", i), CreatedAt: time.Now().UTC(), }) } @@ -60,7 +60,7 @@ func newFakeImageStoreWithFile(t *testing.T, n int) ImageStore { } }) - for i := 0; i < n; i++ { + for i := 1; i <= n; i++ { file, err := newTestImage() if err != nil { t.Fatalf("failed to create test image: %s", err) diff --git a/pkg/services/ngalert/notifier/channels/threema.go b/pkg/services/ngalert/notifier/channels/threema.go index dceaa56ab83..8964a23a091 100644 --- a/pkg/services/ngalert/notifier/channels/threema.go +++ b/pkg/services/ngalert/notifier/channels/threema.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" + ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/notifications" ) @@ -29,6 +30,7 @@ type ThreemaNotifier struct { RecipientID string APISecret string log log.Logger + images ImageStore ns notifications.WebhookSender tmpl *template.Template } @@ -48,7 +50,7 @@ func ThreemaFactory(fc FactoryConfig) (NotificationChannel, error) { Cfg: *fc.Config, } } - return NewThreemaNotifier(cfg, fc.NotificationService, fc.Template), nil + return NewThreemaNotifier(cfg, fc.ImageStore, fc.NotificationService, fc.Template), nil } func NewThreemaConfig(config *NotificationChannelConfig, decryptFunc GetDecryptedValueFn) (*ThreemaConfig, error) { @@ -82,7 +84,7 @@ func NewThreemaConfig(config *NotificationChannelConfig, decryptFunc GetDecrypte } // NewThreemaNotifier is the constructor for the Threema notifier -func NewThreemaNotifier(config *ThreemaConfig, ns notifications.WebhookSender, t *template.Template) *ThreemaNotifier { +func NewThreemaNotifier(config *ThreemaConfig, images ImageStore, ns notifications.WebhookSender, t *template.Template) *ThreemaNotifier { return &ThreemaNotifier{ Base: NewBase(&models.AlertNotification{ Uid: config.UID, @@ -95,6 +97,7 @@ func NewThreemaNotifier(config *ThreemaConfig, ns notifications.WebhookSender, t RecipientID: config.RecipientID, APISecret: config.APISecret, log: log.New("alerting.notifier.threema"), + images: images, ns: ns, tmpl: t, } @@ -127,6 +130,16 @@ func (tn *ThreemaNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool tmpl(`{{ template "default.message" . }}`), path.Join(tn.tmpl.ExternalURL.String(), "/alerting/list"), ) + + _ = withStoredImages(ctx, tn.log, tn.images, + func(index int, image *ngmodels.Image) error { + fmt.Println("here", index, image) + if image != nil && image.URL != "" { + message += fmt.Sprintf("*Image:* %s\n", image.URL) + } + return nil + }, as...) + data.Set("text", message) if tmplErr != nil { diff --git a/pkg/services/ngalert/notifier/channels/threema_test.go b/pkg/services/ngalert/notifier/channels/threema_test.go index c59dc60a6b4..f9f34e779a2 100644 --- a/pkg/services/ngalert/notifier/channels/threema_test.go +++ b/pkg/services/ngalert/notifier/channels/threema_test.go @@ -18,6 +18,8 @@ import ( func TestThreemaNotifier(t *testing.T) { tmpl := templateForTests(t) + images := newFakeImageStore(2) + externalURL, err := url.Parse("http://localhost") require.NoError(t, err) tmpl.ExternalURL = externalURL @@ -31,7 +33,7 @@ func TestThreemaNotifier(t *testing.T) { expMsgError error }{ { - name: "One alert", + name: "A single alert with an image", settings: `{ "gateway_id": "*1234567", "recipient_id": "87654321", @@ -41,14 +43,14 @@ func TestThreemaNotifier(t *testing.T) { { Alert: model.Alert{ Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"}, - Annotations: model.LabelSet{"ann1": "annv1", "__dashboardUid__": "abcd", "__panelId__": "efgh"}, + Annotations: model.LabelSet{"ann1": "annv1", "__dashboardUid__": "abcd", "__panelId__": "efgh", "__alertScreenshotToken__": "test-image-1"}, }, }, }, - expMsg: "from=%2A1234567&secret=supersecret&text=%E2%9A%A0%EF%B8%8F+%5BFIRING%3A1%5D++%28val1%29%0A%0A%2AMessage%3A%2A%0A%2A%2AFiring%2A%2A%0A%0AValue%3A+%5Bno+value%5D%0ALabels%3A%0A+-+alertname+%3D+alert1%0A+-+lbl1+%3D+val1%0AAnnotations%3A%0A+-+ann1+%3D+annv1%0ASilence%3A+http%3A%2F%2Flocalhost%2Falerting%2Fsilence%2Fnew%3Falertmanager%3Dgrafana%26matcher%3Dalertname%253Dalert1%26matcher%3Dlbl1%253Dval1%0ADashboard%3A+http%3A%2F%2Flocalhost%2Fd%2Fabcd%0APanel%3A+http%3A%2F%2Flocalhost%2Fd%2Fabcd%3FviewPanel%3Defgh%0A%0A%2AURL%3A%2A+http%3A%2Flocalhost%2Falerting%2Flist%0A&to=87654321", + expMsg: "from=%2A1234567&secret=supersecret&text=%E2%9A%A0%EF%B8%8F+%5BFIRING%3A1%5D++%28val1%29%0A%0A%2AMessage%3A%2A%0A%2A%2AFiring%2A%2A%0A%0AValue%3A+%5Bno+value%5D%0ALabels%3A%0A+-+alertname+%3D+alert1%0A+-+lbl1+%3D+val1%0AAnnotations%3A%0A+-+ann1+%3D+annv1%0ASilence%3A+http%3A%2F%2Flocalhost%2Falerting%2Fsilence%2Fnew%3Falertmanager%3Dgrafana%26matcher%3Dalertname%253Dalert1%26matcher%3Dlbl1%253Dval1%0ADashboard%3A+http%3A%2F%2Flocalhost%2Fd%2Fabcd%0APanel%3A+http%3A%2F%2Flocalhost%2Fd%2Fabcd%3FviewPanel%3Defgh%0A%0A%2AURL%3A%2A+http%3A%2Flocalhost%2Falerting%2Flist%0A%2AImage%3A%2A+https%3A%2F%2Fwww.example.com%2Ftest-image-1.jpg%0A&to=87654321", expMsgError: nil, }, { - name: "Multiple alerts", + name: "Multiple alerts with images", settings: `{ "gateway_id": "*1234567", "recipient_id": "87654321", @@ -58,16 +60,16 @@ func TestThreemaNotifier(t *testing.T) { { Alert: model.Alert{ Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"}, - Annotations: model.LabelSet{"ann1": "annv1"}, + Annotations: model.LabelSet{"ann1": "annv1", "__alertScreenshotToken__": "test-image-1"}, }, }, { Alert: model.Alert{ Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val2"}, - Annotations: model.LabelSet{"ann1": "annv2"}, + Annotations: model.LabelSet{"ann1": "annv2", "__alertScreenshotToken__": "test-image-2"}, }, }, }, - expMsg: "from=%2A1234567&secret=supersecret&text=%E2%9A%A0%EF%B8%8F+%5BFIRING%3A2%5D++%0A%0A%2AMessage%3A%2A%0A%2A%2AFiring%2A%2A%0A%0AValue%3A+%5Bno+value%5D%0ALabels%3A%0A+-+alertname+%3D+alert1%0A+-+lbl1+%3D+val1%0AAnnotations%3A%0A+-+ann1+%3D+annv1%0ASilence%3A+http%3A%2F%2Flocalhost%2Falerting%2Fsilence%2Fnew%3Falertmanager%3Dgrafana%26matcher%3Dalertname%253Dalert1%26matcher%3Dlbl1%253Dval1%0A%0AValue%3A+%5Bno+value%5D%0ALabels%3A%0A+-+alertname+%3D+alert1%0A+-+lbl1+%3D+val2%0AAnnotations%3A%0A+-+ann1+%3D+annv2%0ASilence%3A+http%3A%2F%2Flocalhost%2Falerting%2Fsilence%2Fnew%3Falertmanager%3Dgrafana%26matcher%3Dalertname%253Dalert1%26matcher%3Dlbl1%253Dval2%0A%0A%2AURL%3A%2A+http%3A%2Flocalhost%2Falerting%2Flist%0A&to=87654321", + expMsg: "from=%2A1234567&secret=supersecret&text=%E2%9A%A0%EF%B8%8F+%5BFIRING%3A2%5D++%0A%0A%2AMessage%3A%2A%0A%2A%2AFiring%2A%2A%0A%0AValue%3A+%5Bno+value%5D%0ALabels%3A%0A+-+alertname+%3D+alert1%0A+-+lbl1+%3D+val1%0AAnnotations%3A%0A+-+ann1+%3D+annv1%0ASilence%3A+http%3A%2F%2Flocalhost%2Falerting%2Fsilence%2Fnew%3Falertmanager%3Dgrafana%26matcher%3Dalertname%253Dalert1%26matcher%3Dlbl1%253Dval1%0A%0AValue%3A+%5Bno+value%5D%0ALabels%3A%0A+-+alertname+%3D+alert1%0A+-+lbl1+%3D+val2%0AAnnotations%3A%0A+-+ann1+%3D+annv2%0ASilence%3A+http%3A%2F%2Flocalhost%2Falerting%2Fsilence%2Fnew%3Falertmanager%3Dgrafana%26matcher%3Dalertname%253Dalert1%26matcher%3Dlbl1%253Dval2%0A%0A%2AURL%3A%2A+http%3A%2Flocalhost%2Falerting%2Flist%0A%2AImage%3A%2A+https%3A%2F%2Fwww.example.com%2Ftest-image-1.jpg%0A%2AImage%3A%2A+https%3A%2F%2Fwww.example.com%2Ftest-image-2.jpg%0A&to=87654321", expMsgError: nil, }, { name: "Invalid gateway id", @@ -121,7 +123,7 @@ func TestThreemaNotifier(t *testing.T) { ctx := notify.WithGroupKey(context.Background(), "alertname") ctx = notify.WithGroupLabels(ctx, model.LabelSet{"alertname": ""}) - pn := NewThreemaNotifier(cfg, webhookSender, tmpl) + pn := NewThreemaNotifier(cfg, images, webhookSender, tmpl) ok, err := pn.Notify(ctx, c.alerts...) if c.expMsgError != nil { require.False(t, ok)