Alerting: Add support for images in Threema alerts (#50734)
This commit is contained in:
@@ -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.
|
// Each image has a token and a URL, but does not have a file on disk.
|
||||||
func newFakeImageStore(n int) ImageStore {
|
func newFakeImageStore(n int) ImageStore {
|
||||||
s := fakeImageStore{}
|
s := fakeImageStore{}
|
||||||
for i := 0; i < n; i++ {
|
for i := 1; i <= n; i++ {
|
||||||
s.Images = append(s.Images, &ngmodels.Image{
|
s.Images = append(s.Images, &ngmodels.Image{
|
||||||
Token: fmt.Sprintf("test-image-%d", i),
|
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(),
|
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()
|
file, err := newTestImage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create test image: %s", err)
|
t.Fatalf("failed to create test image: %s", err)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"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/services/notifications"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,6 +30,7 @@ type ThreemaNotifier struct {
|
|||||||
RecipientID string
|
RecipientID string
|
||||||
APISecret string
|
APISecret string
|
||||||
log log.Logger
|
log log.Logger
|
||||||
|
images ImageStore
|
||||||
ns notifications.WebhookSender
|
ns notifications.WebhookSender
|
||||||
tmpl *template.Template
|
tmpl *template.Template
|
||||||
}
|
}
|
||||||
@@ -48,7 +50,7 @@ func ThreemaFactory(fc FactoryConfig) (NotificationChannel, error) {
|
|||||||
Cfg: *fc.Config,
|
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) {
|
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
|
// 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{
|
return &ThreemaNotifier{
|
||||||
Base: NewBase(&models.AlertNotification{
|
Base: NewBase(&models.AlertNotification{
|
||||||
Uid: config.UID,
|
Uid: config.UID,
|
||||||
@@ -95,6 +97,7 @@ func NewThreemaNotifier(config *ThreemaConfig, ns notifications.WebhookSender, t
|
|||||||
RecipientID: config.RecipientID,
|
RecipientID: config.RecipientID,
|
||||||
APISecret: config.APISecret,
|
APISecret: config.APISecret,
|
||||||
log: log.New("alerting.notifier.threema"),
|
log: log.New("alerting.notifier.threema"),
|
||||||
|
images: images,
|
||||||
ns: ns,
|
ns: ns,
|
||||||
tmpl: t,
|
tmpl: t,
|
||||||
}
|
}
|
||||||
@@ -127,6 +130,16 @@ func (tn *ThreemaNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool
|
|||||||
tmpl(`{{ template "default.message" . }}`),
|
tmpl(`{{ template "default.message" . }}`),
|
||||||
path.Join(tn.tmpl.ExternalURL.String(), "/alerting/list"),
|
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)
|
data.Set("text", message)
|
||||||
|
|
||||||
if tmplErr != nil {
|
if tmplErr != nil {
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ import (
|
|||||||
func TestThreemaNotifier(t *testing.T) {
|
func TestThreemaNotifier(t *testing.T) {
|
||||||
tmpl := templateForTests(t)
|
tmpl := templateForTests(t)
|
||||||
|
|
||||||
|
images := newFakeImageStore(2)
|
||||||
|
|
||||||
externalURL, err := url.Parse("http://localhost")
|
externalURL, err := url.Parse("http://localhost")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
tmpl.ExternalURL = externalURL
|
tmpl.ExternalURL = externalURL
|
||||||
@@ -31,7 +33,7 @@ func TestThreemaNotifier(t *testing.T) {
|
|||||||
expMsgError error
|
expMsgError error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "One alert",
|
name: "A single alert with an image",
|
||||||
settings: `{
|
settings: `{
|
||||||
"gateway_id": "*1234567",
|
"gateway_id": "*1234567",
|
||||||
"recipient_id": "87654321",
|
"recipient_id": "87654321",
|
||||||
@@ -41,14 +43,14 @@ func TestThreemaNotifier(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Alert: model.Alert{
|
Alert: model.Alert{
|
||||||
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"},
|
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,
|
expMsgError: nil,
|
||||||
}, {
|
}, {
|
||||||
name: "Multiple alerts",
|
name: "Multiple alerts with images",
|
||||||
settings: `{
|
settings: `{
|
||||||
"gateway_id": "*1234567",
|
"gateway_id": "*1234567",
|
||||||
"recipient_id": "87654321",
|
"recipient_id": "87654321",
|
||||||
@@ -58,16 +60,16 @@ func TestThreemaNotifier(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Alert: model.Alert{
|
Alert: model.Alert{
|
||||||
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"},
|
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"},
|
||||||
Annotations: model.LabelSet{"ann1": "annv1"},
|
Annotations: model.LabelSet{"ann1": "annv1", "__alertScreenshotToken__": "test-image-1"},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
Alert: model.Alert{
|
Alert: model.Alert{
|
||||||
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val2"},
|
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,
|
expMsgError: nil,
|
||||||
}, {
|
}, {
|
||||||
name: "Invalid gateway id",
|
name: "Invalid gateway id",
|
||||||
@@ -121,7 +123,7 @@ func TestThreemaNotifier(t *testing.T) {
|
|||||||
|
|
||||||
ctx := notify.WithGroupKey(context.Background(), "alertname")
|
ctx := notify.WithGroupKey(context.Background(), "alertname")
|
||||||
ctx = notify.WithGroupLabels(ctx, model.LabelSet{"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...)
|
ok, err := pn.Notify(ctx, c.alerts...)
|
||||||
if c.expMsgError != nil {
|
if c.expMsgError != nil {
|
||||||
require.False(t, ok)
|
require.False(t, ok)
|
||||||
|
|||||||
Reference in New Issue
Block a user