From 99516360c9e85b400ed9bf38b42e1c40348774d1 Mon Sep 17 00:00:00 2001 From: George Robinson Date: Wed, 22 Jun 2022 10:00:50 +0100 Subject: [PATCH] Alerting: Add support for images in VictorOps alerts (#50759) --- .../ngalert/notifier/channels/victorops.go | 16 ++++++++++++++-- .../ngalert/notifier/channels/victorops_test.go | 16 ++++++++++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/pkg/services/ngalert/notifier/channels/victorops.go b/pkg/services/ngalert/notifier/channels/victorops.go index 49e44300a80..072ce92d5e3 100644 --- a/pkg/services/ngalert/notifier/channels/victorops.go +++ b/pkg/services/ngalert/notifier/channels/victorops.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "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" "github.com/grafana/grafana/pkg/setting" ) @@ -40,7 +41,7 @@ func VictorOpsFactory(fc FactoryConfig) (NotificationChannel, error) { Cfg: *fc.Config, } } - return NewVictoropsNotifier(cfg, fc.NotificationService, fc.Template), nil + return NewVictoropsNotifier(cfg, fc.ImageStore, fc.NotificationService, fc.Template), nil } func NewVictorOpsConfig(config *NotificationChannelConfig) (*VictorOpsConfig, error) { @@ -57,7 +58,7 @@ func NewVictorOpsConfig(config *NotificationChannelConfig) (*VictorOpsConfig, er // NewVictoropsNotifier creates an instance of VictoropsNotifier that // handles posting notifications to Victorops REST API -func NewVictoropsNotifier(config *VictorOpsConfig, ns notifications.WebhookSender, t *template.Template) *VictoropsNotifier { +func NewVictoropsNotifier(config *VictorOpsConfig, images ImageStore, ns notifications.WebhookSender, t *template.Template) *VictoropsNotifier { return &VictoropsNotifier{ Base: NewBase(&models.AlertNotification{ Uid: config.UID, @@ -69,6 +70,7 @@ func NewVictoropsNotifier(config *VictorOpsConfig, ns notifications.WebhookSende URL: config.URL, MessageType: config.MessageType, log: log.New("alerting.notifier.victorops"), + images: images, ns: ns, tmpl: t, } @@ -82,6 +84,7 @@ type VictoropsNotifier struct { URL string MessageType string log log.Logger + images ImageStore ns notifications.WebhookSender tmpl *template.Template } @@ -115,6 +118,15 @@ func (vn *VictoropsNotifier) Notify(ctx context.Context, as ...*types.Alert) (bo bodyJSON.Set("state_message", tmpl(`{{ template "default.message" . }}`)) bodyJSON.Set("monitoring_tool", "Grafana v"+setting.BuildVersion) + _ = withStoredImages(ctx, vn.log, vn.images, + func(index int, image *ngmodels.Image) error { + if image != nil && image.URL != "" { + bodyJSON.Set("image_url", image.URL) + return ErrImagesDone + } + return nil + }, as...) + ruleURL := joinUrlPath(vn.tmpl.ExternalURL.String(), "/alerting/list", vn.log) bodyJSON.Set("alert_url", ruleURL) diff --git a/pkg/services/ngalert/notifier/channels/victorops_test.go b/pkg/services/ngalert/notifier/channels/victorops_test.go index 04f1f6e167e..1c27e3d4f7b 100644 --- a/pkg/services/ngalert/notifier/channels/victorops_test.go +++ b/pkg/services/ngalert/notifier/channels/victorops_test.go @@ -18,6 +18,8 @@ import ( func TestVictoropsNotifier(t *testing.T) { tmpl := templateForTests(t) + images := newFakeImageStore(2) + externalURL, err := url.Parse("http://localhost") require.NoError(t, err) tmpl.ExternalURL = externalURL @@ -31,13 +33,13 @@ func TestVictoropsNotifier(t *testing.T) { expMsgError error }{ { - name: "One alert", + name: "A single alert with image", settings: `{"url": "http://localhost"}`, alerts: []*types.Alert{ { 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"}, }, }, }, @@ -45,24 +47,25 @@ func TestVictoropsNotifier(t *testing.T) { "alert_url": "http://localhost/alerting/list", "entity_display_name": "[FIRING:1] (val1)", "entity_id": "6e3538104c14b583da237e9693b76debbc17f0f8058ef20492e5853096cf8733", + "image_url": "https://www.example.com/test-image-1.jpg", "message_type": "CRITICAL", "monitoring_tool": "Grafana v" + setting.BuildVersion, "state_message": "**Firing**\n\nValue: [no value]\nLabels:\n - alertname = alert1\n - lbl1 = val1\nAnnotations:\n - ann1 = annv1\nSilence: http://localhost/alerting/silence/new?alertmanager=grafana&matcher=alertname%3Dalert1&matcher=lbl1%3Dval1\nDashboard: http://localhost/d/abcd\nPanel: http://localhost/d/abcd?viewPanel=efgh\n", }, expMsgError: nil, }, { - name: "Multiple alerts", + name: "Multiple alerts with images", settings: `{"url": "http://localhost"}`, alerts: []*types.Alert{ { 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"}, }, }, }, @@ -70,6 +73,7 @@ func TestVictoropsNotifier(t *testing.T) { "alert_url": "http://localhost/alerting/list", "entity_display_name": "[FIRING:2] ", "entity_id": "6e3538104c14b583da237e9693b76debbc17f0f8058ef20492e5853096cf8733", + "image_url": "https://www.example.com/test-image-1.jpg", "message_type": "CRITICAL", "monitoring_tool": "Grafana v" + setting.BuildVersion, "state_message": "**Firing**\n\nValue: [no value]\nLabels:\n - alertname = alert1\n - lbl1 = val1\nAnnotations:\n - ann1 = annv1\nSilence: http://localhost/alerting/silence/new?alertmanager=grafana&matcher=alertname%3Dalert1&matcher=lbl1%3Dval1\n\nValue: [no value]\nLabels:\n - alertname = alert1\n - lbl1 = val2\nAnnotations:\n - ann1 = annv2\nSilence: http://localhost/alerting/silence/new?alertmanager=grafana&matcher=alertname%3Dalert1&matcher=lbl1%3Dval2\n", @@ -179,7 +183,7 @@ func TestVictoropsNotifier(t *testing.T) { ctx := notify.WithGroupKey(context.Background(), "alertname") ctx = notify.WithGroupLabels(ctx, model.LabelSet{"alertname": ""}) - pn := NewVictoropsNotifier(cfg, webhookSender, tmpl) + pn := NewVictoropsNotifier(cfg, images, webhookSender, tmpl) ok, err := pn.Notify(ctx, c.alerts...) if c.expMsgError != nil { require.False(t, ok)