mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: isolate ImageStore in notify package (#60353)
This commit is contained in:
parent
286af5a53b
commit
de008005ce
@ -514,7 +514,7 @@ func (am *Alertmanager) buildReceiverIntegration(r *apimodels.PostableGrafanaRec
|
||||
SecureSettings: secureSettings,
|
||||
}
|
||||
)
|
||||
factoryConfig, err := channels.NewFactoryConfig(cfg, NewNotificationSender(am.NotificationService), am.decryptFn, tmpl, am.Store)
|
||||
factoryConfig, err := channels.NewFactoryConfig(cfg, NewNotificationSender(am.NotificationService), am.decryptFn, tmpl, newImageStore(am.Store))
|
||||
if err != nil {
|
||||
return nil, InvalidReceiverError{
|
||||
Receiver: r,
|
||||
|
@ -14,7 +14,6 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
// GetDecryptedValueFn is a function that returns the decrypted value of
|
||||
@ -104,7 +103,7 @@ func (n *AlertmanagerNotifier) Notify(ctx context.Context, as ...*types.Alert) (
|
||||
}
|
||||
|
||||
_ = withStoredImages(ctx, n.logger, n.images,
|
||||
func(index int, image ngmodels.Image) error {
|
||||
func(index int, image Image) error {
|
||||
// If there is an image for this alert and the image has been uploaded
|
||||
// to a public URL then include it as an annotation
|
||||
if image.URL != "" {
|
||||
|
@ -19,7 +19,6 @@ 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/setting"
|
||||
)
|
||||
|
||||
@ -193,7 +192,7 @@ func (d DiscordNotifier) constructAttachments(ctx context.Context, as []*types.A
|
||||
attachments := make([]discordAttachment, 0)
|
||||
|
||||
_ = withStoredImages(ctx, d.log, d.images,
|
||||
func(index int, image ngmodels.Image) error {
|
||||
func(index int, image Image) error {
|
||||
if embedQuota < 1 {
|
||||
return ErrImagesDone
|
||||
}
|
||||
@ -213,7 +212,7 @@ func (d DiscordNotifier) constructAttachments(ctx context.Context, as []*types.A
|
||||
base := filepath.Base(image.Path)
|
||||
url := fmt.Sprintf("attachment://%s", base)
|
||||
reader, err := openImage(image.Path)
|
||||
if err != nil && !errors.Is(err, ngmodels.ErrImageNotFound) {
|
||||
if err != nil && !errors.Is(err, ErrImageNotFound) {
|
||||
d.log.Warn("failed to retrieve image data from store", "error", err)
|
||||
return nil
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ 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/util"
|
||||
)
|
||||
|
||||
@ -110,7 +109,7 @@ func (en *EmailNotifier) Notify(ctx context.Context, alerts ...*types.Alert) (bo
|
||||
// Extend alerts data with images, if available.
|
||||
var embeddedFiles []string
|
||||
_ = withStoredImages(ctx, en.log, en.images,
|
||||
func(index int, image ngmodels.Image) error {
|
||||
func(index int, image Image) error {
|
||||
if len(image.URL) != 0 {
|
||||
data.Alerts[index].ImageURL = image.URL
|
||||
} else if len(image.Path) != 0 {
|
||||
|
@ -1,13 +1,10 @@
|
||||
package channels
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/alertmanager/template"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
type FactoryConfig struct {
|
||||
@ -19,10 +16,6 @@ type FactoryConfig struct {
|
||||
Template *template.Template
|
||||
}
|
||||
|
||||
type ImageStore interface {
|
||||
GetImage(ctx context.Context, token string) (*models.Image, error)
|
||||
}
|
||||
|
||||
func NewFactoryConfig(config *NotificationChannelConfig, notificationService NotificationSender,
|
||||
decryptFunc GetDecryptedValueFn, template *template.Template, imageStore ImageStore) (FactoryConfig, error) {
|
||||
if config.Settings == nil {
|
||||
|
@ -13,7 +13,6 @@ 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/setting"
|
||||
)
|
||||
|
||||
@ -197,7 +196,7 @@ func (gcn *GoogleChatNotifier) buildScreenshotCard(ctx context.Context, alerts [
|
||||
}
|
||||
|
||||
_ = withStoredImages(ctx, gcn.log, gcn.images,
|
||||
func(index int, image ngmodels.Image) error {
|
||||
func(index int, image Image) error {
|
||||
if len(image.URL) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
26
pkg/services/ngalert/notifier/channels/images.go
Normal file
26
pkg/services/ngalert/notifier/channels/images.go
Normal file
@ -0,0 +1,26 @@
|
||||
package channels
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrImageNotFound = errors.New("image not found")
|
||||
)
|
||||
|
||||
type Image struct {
|
||||
Token string
|
||||
Path string
|
||||
URL string
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
func (i Image) HasURL() bool {
|
||||
return i.URL != ""
|
||||
}
|
||||
|
||||
type ImageStore interface {
|
||||
GetImage(ctx context.Context, token string) (*Image, error)
|
||||
}
|
@ -13,7 +13,6 @@ 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"
|
||||
)
|
||||
|
||||
// KafkaNotifier is responsible for sending
|
||||
@ -161,7 +160,7 @@ func buildState(as ...*types.Alert) models.AlertStateType {
|
||||
func buildContextImages(ctx context.Context, l log.Logger, imageStore ImageStore, as ...*types.Alert) []interface{} {
|
||||
var contexts []interface{}
|
||||
_ = withStoredImages(ctx, l, imageStore,
|
||||
func(_ int, image ngmodels.Image) error {
|
||||
func(_ int, image Image) error {
|
||||
if image.URL != "" {
|
||||
imageJSON := simplejson.New()
|
||||
imageJSON.Set("type", "image")
|
||||
|
@ -17,7 +17,6 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -246,7 +245,7 @@ func (on *OpsgenieNotifier) buildOpsgenieMessage(ctx context.Context, alerts mod
|
||||
}
|
||||
var images []string
|
||||
_ = withStoredImages(ctx, on.log, on.images,
|
||||
func(_ int, image ngmodels.Image) error {
|
||||
func(_ int, image Image) error {
|
||||
if len(image.URL) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -231,7 +230,7 @@ func (pn *PagerdutyNotifier) buildPagerdutyMessage(ctx context.Context, alerts m
|
||||
}
|
||||
|
||||
_ = withStoredImages(ctx, pn.log, pn.images,
|
||||
func(_ int, image ngmodels.Image) error {
|
||||
func(_ int, image Image) error {
|
||||
if len(image.URL) != 0 {
|
||||
msg.Images = append(msg.Images, pagerDutyImage{Src: image.URL})
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -316,7 +315,7 @@ func (pn *PushoverNotifier) genPushoverBody(ctx context.Context, as ...*types.Al
|
||||
func (pn *PushoverNotifier) writeImageParts(ctx context.Context, w *multipart.Writer, as ...*types.Alert) {
|
||||
// Pushover supports at most one image attachment with a maximum size of pushoverMaxFileSize.
|
||||
// If the image is larger than pushoverMaxFileSize then return an error.
|
||||
_ = withStoredImages(ctx, pn.log, pn.images, func(index int, image ngmodels.Image) error {
|
||||
_ = withStoredImages(ctx, pn.log, pn.images, func(index int, image Image) error {
|
||||
f, err := os.Open(image.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open the image: %w", err)
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
type SensuGoNotifier struct {
|
||||
@ -127,7 +126,7 @@ func (sn *SensuGoNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool
|
||||
labels := make(map[string]string)
|
||||
|
||||
_ = withStoredImages(ctx, sn.log, sn.images,
|
||||
func(_ int, image ngmodels.Image) error {
|
||||
func(_ int, image Image) error {
|
||||
// If there is an image for this alert and the image has been uploaded
|
||||
// to a public URL then add it to the request. We cannot add more than
|
||||
// one image per request.
|
||||
|
@ -24,7 +24,6 @@ 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/setting"
|
||||
)
|
||||
|
||||
@ -220,7 +219,7 @@ func (sn *SlackNotifier) Notify(ctx context.Context, alerts ...*types.Alert) (bo
|
||||
|
||||
// Do not upload images if using an incoming webhook as incoming webhooks cannot upload files
|
||||
if !isIncomingWebhook(sn.settings) {
|
||||
if err := withStoredImages(ctx, sn.log, sn.images, func(index int, image ngmodels.Image) error {
|
||||
if err := withStoredImages(ctx, sn.log, sn.images, func(index int, image Image) error {
|
||||
// If we have exceeded the maximum number of images for this thread_ts
|
||||
// then tell the recipient and stop iterating subsequent images
|
||||
if index >= maxImagesPerThreadTs {
|
||||
@ -393,7 +392,7 @@ func (sn *SlackNotifier) createSlackMessage(ctx context.Context, alerts []*types
|
||||
|
||||
if isIncomingWebhook(sn.settings) {
|
||||
// Incoming webhooks cannot upload files, instead share images via their URL
|
||||
_ = withStoredImages(ctx, sn.log, sn.images, func(index int, image ngmodels.Image) error {
|
||||
_ = withStoredImages(ctx, sn.log, sn.images, func(index int, image Image) error {
|
||||
if image.URL != "" {
|
||||
req.Attachments[0].ImageURL = image.URL
|
||||
return ErrImagesDone
|
||||
@ -476,7 +475,7 @@ func (sn *SlackNotifier) sendSlackMessage(ctx context.Context, m *slackMessage)
|
||||
// createImageMultipart returns the mutlipart/form-data request and headers for files.upload.
|
||||
// It returns an error if the image does not exist or there was an error preparing the
|
||||
// multipart form.
|
||||
func (sn *SlackNotifier) createImageMultipart(image ngmodels.Image, channel, comment, thread_ts string) (http.Header, []byte, error) {
|
||||
func (sn *SlackNotifier) createImageMultipart(image Image, channel, comment, thread_ts string) (http.Header, []byte, error) {
|
||||
buf := bytes.Buffer{}
|
||||
w := multipart.NewWriter(&buf)
|
||||
defer func() {
|
||||
@ -553,7 +552,7 @@ func (sn *SlackNotifier) sendMultipart(ctx context.Context, headers http.Header,
|
||||
// uploadImage shares the image to the channel names or IDs. It returns an error if the file
|
||||
// does not exist, or if there was an error either preparing or sending the multipart/form-data
|
||||
// request.
|
||||
func (sn *SlackNotifier) uploadImage(ctx context.Context, image ngmodels.Image, channel, comment, thread_ts string) error {
|
||||
func (sn *SlackNotifier) uploadImage(ctx context.Context, image Image, channel, comment, thread_ts string) error {
|
||||
sn.log.Debug("Uploadimg image", "image", image.Token)
|
||||
headers, data, err := sn.createImageMultipart(image, channel, comment, thread_ts)
|
||||
if err != nil {
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@ -416,7 +415,7 @@ func setupSlackForTests(t *testing.T, settings string) (*SlackNotifier, *slackRe
|
||||
})
|
||||
|
||||
images := &fakeImageStore{
|
||||
Images: []*models.Image{{
|
||||
Images: []*Image{{
|
||||
Token: "image-on-disk",
|
||||
Path: f.Name(),
|
||||
}, {
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -309,7 +308,7 @@ func (tn *TeamsNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool,
|
||||
|
||||
var s AdaptiveCardImageSetItem
|
||||
_ = withStoredImages(ctx, tn.log, tn.images,
|
||||
func(_ int, image ngmodels.Image) error {
|
||||
func(_ int, image Image) error {
|
||||
if image.URL != "" {
|
||||
s.AppendImage(AdaptiveCardImageItem{URL: image.URL})
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -144,7 +143,7 @@ func (tn *TelegramNotifier) Notify(ctx context.Context, as ...*types.Alert) (boo
|
||||
}
|
||||
|
||||
// Create the cmd to upload each image
|
||||
_ = withStoredImages(ctx, tn.log, tn.images, func(index int, image ngmodels.Image) error {
|
||||
_ = withStoredImages(ctx, tn.log, tn.images, func(index int, image Image) error {
|
||||
cmd, err = tn.newWebhookSyncCmd("sendPhoto", func(w *multipart.Writer) error {
|
||||
f, err := os.Open(image.Path)
|
||||
if err != nil {
|
||||
|
@ -13,23 +13,22 @@ import (
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"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"
|
||||
)
|
||||
|
||||
type fakeImageStore struct {
|
||||
Images []*ngmodels.Image
|
||||
Images []*Image
|
||||
}
|
||||
|
||||
// getImage returns an image with the same token.
|
||||
func (f *fakeImageStore) GetImage(_ context.Context, token string) (*ngmodels.Image, error) {
|
||||
func (f *fakeImageStore) GetImage(_ context.Context, token string) (*Image, error) {
|
||||
for _, img := range f.Images {
|
||||
if img.Token == token {
|
||||
return img, nil
|
||||
}
|
||||
}
|
||||
return nil, ngmodels.ErrImageNotFound
|
||||
return nil, ErrImageNotFound
|
||||
}
|
||||
|
||||
// newFakeImageStore returns an image store with N test images.
|
||||
@ -37,7 +36,7 @@ func (f *fakeImageStore) GetImage(_ context.Context, token string) (*ngmodels.Im
|
||||
func newFakeImageStore(n int) ImageStore {
|
||||
s := fakeImageStore{}
|
||||
for i := 1; i <= n; i++ {
|
||||
s.Images = append(s.Images, &ngmodels.Image{
|
||||
s.Images = append(s.Images, &Image{
|
||||
Token: fmt.Sprintf("test-image-%d", i),
|
||||
URL: fmt.Sprintf("https://www.example.com/test-image-%d.jpg", i),
|
||||
CreatedAt: time.Now().UTC(),
|
||||
@ -72,7 +71,7 @@ func newFakeImageStoreWithFile(t *testing.T, n int) ImageStore {
|
||||
t.Fatalf("failed to create test image: %s", err)
|
||||
}
|
||||
files = append(files, file)
|
||||
s.Images = append(s.Images, &ngmodels.Image{
|
||||
s.Images = append(s.Images, &Image{
|
||||
Token: fmt.Sprintf("test-image-%d", i),
|
||||
Path: file,
|
||||
URL: fmt.Sprintf("https://www.example.com/test-image-%d", i),
|
||||
|
@ -14,7 +14,6 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -158,7 +157,7 @@ func (tn *ThreemaNotifier) buildMessage(ctx context.Context, as ...*types.Alert)
|
||||
}
|
||||
|
||||
_ = withStoredImages(ctx, tn.log, tn.images,
|
||||
func(_ int, image ngmodels.Image) error {
|
||||
func(_ int, image Image) error {
|
||||
if image.URL != "" {
|
||||
message += fmt.Sprintf("*Image:* %s\n", image.URL)
|
||||
}
|
||||
|
@ -49,11 +49,11 @@ var (
|
||||
ErrImagesUnavailable = errors.New("alert screenshots are unavailable")
|
||||
)
|
||||
|
||||
type forEachImageFunc func(index int, image models.Image) error
|
||||
type forEachImageFunc func(index int, image Image) error
|
||||
|
||||
// getImage returns the image for the alert or an error. It returns a nil
|
||||
// image if the alert does not have an image token or the image does not exist.
|
||||
func getImage(ctx context.Context, l log.Logger, imageStore ImageStore, alert types.Alert) (*models.Image, error) {
|
||||
func getImage(ctx context.Context, l log.Logger, imageStore ImageStore, alert types.Alert) (*Image, error) {
|
||||
token := getTokenFromAnnotations(alert.Annotations)
|
||||
if token == "" {
|
||||
return nil, nil
|
||||
@ -63,7 +63,7 @@ func getImage(ctx context.Context, l log.Logger, imageStore ImageStore, alert ty
|
||||
defer cancelFunc()
|
||||
|
||||
img, err := imageStore.GetImage(ctx, token)
|
||||
if errors.Is(err, models.ErrImageNotFound) || errors.Is(err, ErrImagesUnavailable) {
|
||||
if errors.Is(err, ErrImageNotFound) || errors.Is(err, ErrImagesUnavailable) {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
l.Warn("failed to get image with token", "token", token, "error", err)
|
||||
@ -107,7 +107,7 @@ func openImage(path string) (io.ReadCloser, error) {
|
||||
fp := filepath.Clean(path)
|
||||
_, err := os.Stat(fp)
|
||||
if os.IsNotExist(err) || os.IsPermission(err) {
|
||||
return nil, models.ErrImageNotFound
|
||||
return nil, ErrImageNotFound
|
||||
}
|
||||
|
||||
f, err := os.Open(fp)
|
||||
@ -128,7 +128,7 @@ func getTokenFromAnnotations(annotations model.LabelSet) string {
|
||||
type UnavailableImageStore struct{}
|
||||
|
||||
// Get returns the image with the corresponding token, or ErrImageNotFound.
|
||||
func (u *UnavailableImageStore) GetImage(ctx context.Context, token string) (*models.Image, error) {
|
||||
func (u *UnavailableImageStore) GetImage(ctx context.Context, token string) (*Image, error) {
|
||||
return nil, ErrImagesUnavailable
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ func TestWithStoredImages(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}}
|
||||
imageStore := &fakeImageStore{Images: []*models.Image{{
|
||||
imageStore := &fakeImageStore{Images: []*Image{{
|
||||
Token: "test-image-1",
|
||||
URL: "https://www.example.com/test-image-1.jpg",
|
||||
CreatedAt: time.Now().UTC(),
|
||||
@ -45,7 +45,7 @@ func TestWithStoredImages(t *testing.T) {
|
||||
)
|
||||
|
||||
// should iterate all images
|
||||
err = withStoredImages(ctx, log.New(ctx), imageStore, func(index int, image models.Image) error {
|
||||
err = withStoredImages(ctx, log.New(ctx), imageStore, func(index int, image Image) error {
|
||||
i += 1
|
||||
return nil
|
||||
}, alerts...)
|
||||
@ -54,7 +54,7 @@ func TestWithStoredImages(t *testing.T) {
|
||||
|
||||
// should iterate just the first image
|
||||
i = 0
|
||||
err = withStoredImages(ctx, log.New(ctx), imageStore, func(index int, image models.Image) error {
|
||||
err = withStoredImages(ctx, log.New(ctx), imageStore, func(index int, image Image) error {
|
||||
i += 1
|
||||
return ErrImagesDone
|
||||
}, alerts...)
|
||||
|
@ -15,7 +15,6 @@ 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/setting"
|
||||
)
|
||||
|
||||
@ -139,7 +138,7 @@ func (vn *VictoropsNotifier) Notify(ctx context.Context, as ...*types.Alert) (bo
|
||||
}
|
||||
|
||||
_ = withStoredImages(ctx, vn.log, vn.images,
|
||||
func(index int, image ngmodels.Image) error {
|
||||
func(index int, image Image) error {
|
||||
if image.URL != "" {
|
||||
bodyJSON["image_url"] = image.URL
|
||||
return ErrImagesDone
|
||||
|
@ -12,7 +12,6 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
const webexAPIURL = "https://webexapis.com/v1/messages"
|
||||
@ -130,7 +129,7 @@ func (wn *WebexNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool,
|
||||
}
|
||||
|
||||
// Augment our Alert data with ImageURLs if available.
|
||||
_ = withStoredImages(ctx, wn.log, wn.images, func(index int, image ngmodels.Image) error {
|
||||
_ = withStoredImages(ctx, wn.log, wn.images, func(index int, image Image) error {
|
||||
// Cisco Webex only supports a single image per request: https://developer.webex.com/docs/basics#message-attachments
|
||||
if image.HasURL() {
|
||||
data.Alerts[index].ImageURL = image.URL
|
||||
|
@ -15,7 +15,6 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
||||
// WebhookNotifier is responsible for sending
|
||||
@ -160,7 +159,7 @@ func (wn *WebhookNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool
|
||||
|
||||
// Augment our Alert data with ImageURLs if available.
|
||||
_ = withStoredImages(ctx, wn.log, wn.images,
|
||||
func(index int, image ngmodels.Image) error {
|
||||
func(index int, image Image) error {
|
||||
if len(image.URL) != 0 {
|
||||
data.Alerts[index].ImageURL = image.URL
|
||||
}
|
||||
|
39
pkg/services/ngalert/notifier/images.go
Normal file
39
pkg/services/ngalert/notifier/images.go
Normal file
@ -0,0 +1,39 @@
|
||||
package notifier
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier/channels"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
)
|
||||
|
||||
type imageStore struct {
|
||||
store store.ImageStore
|
||||
}
|
||||
|
||||
func newImageStore(store store.ImageStore) channels.ImageStore {
|
||||
return &imageStore{
|
||||
store: store,
|
||||
}
|
||||
}
|
||||
|
||||
func (i imageStore) GetImage(ctx context.Context, token string) (*channels.Image, error) {
|
||||
image, err := i.store.GetImage(ctx, token)
|
||||
if err != nil {
|
||||
if errors.Is(err, models.ErrImageNotFound) {
|
||||
err = channels.ErrImageNotFound
|
||||
}
|
||||
}
|
||||
var result *channels.Image
|
||||
if image != nil {
|
||||
result = &channels.Image{
|
||||
Token: image.Token,
|
||||
Path: image.Path,
|
||||
URL: image.URL,
|
||||
CreatedAt: image.CreatedAt,
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
}
|
Loading…
Reference in New Issue
Block a user