diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go index d848ef405bf..951b3d2aa3d 100644 --- a/pkg/services/alerting/notifier.go +++ b/pkg/services/alerting/notifier.go @@ -53,25 +53,19 @@ func (n *notificationService) SendIfNeeded(evalCtx *EvalContext) error { } if notifierStates.ShouldUploadImage() { - if n.renderService.IsAvailable() { - // Create a copy of EvalContext and give it a new, shorter, timeout context to upload the image - uploadEvalCtx := *evalCtx - timeout := setting.AlertingNotificationTimeout / 2 - var uploadCtxCancel func() - uploadEvalCtx.Ctx, uploadCtxCancel = context.WithTimeout(evalCtx.Ctx, timeout) - - // Try to upload the image without consuming all the time allocated for EvalContext - if err = n.renderAndUploadImage(&uploadEvalCtx, timeout); err != nil { - n.log.Error("Failed to render and upload alert panel image.", "ruleId", uploadEvalCtx.Rule.ID, "error", err) - } - uploadCtxCancel() - evalCtx.ImageOnDiskPath = uploadEvalCtx.ImageOnDiskPath - evalCtx.ImagePublicURL = uploadEvalCtx.ImagePublicURL - } else { - n.log.Warn("Could not render image for alert notification, no image renderer found/installed. " + - "For image rendering support please install the grafana-image-renderer plugin. " + - "Read more at https://grafana.com/docs/grafana/latest/administration/image_rendering/") + // Create a copy of EvalContext and give it a new, shorter, timeout context to upload the image + uploadEvalCtx := *evalCtx + timeout := setting.AlertingNotificationTimeout / 2 + var uploadCtxCancel func() + uploadEvalCtx.Ctx, uploadCtxCancel = context.WithTimeout(evalCtx.Ctx, timeout) + + // Try to upload the image without consuming all the time allocated for EvalContext + if err = n.renderAndUploadImage(&uploadEvalCtx, timeout); err != nil { + n.log.Error("Failed to render and upload alert panel image.", "ruleId", uploadEvalCtx.Rule.ID, "error", err) } + uploadCtxCancel() + evalCtx.ImageOnDiskPath = uploadEvalCtx.ImageOnDiskPath + evalCtx.ImagePublicURL = uploadEvalCtx.ImagePublicURL } return n.sendNotifications(evalCtx, notifierStates) @@ -174,6 +168,7 @@ func (n *notificationService) renderAndUploadImage(evalCtx *EvalContext, timeout n.log.Debug("Rendered alert panel image", "ruleId", evalCtx.Rule.ID, "path", result.FilePath, "took", took) evalCtx.ImageOnDiskPath = result.FilePath + n.log.Debug("Uploading alert panel image to external image store", "ruleId", evalCtx.Rule.ID, "path", evalCtx.ImageOnDiskPath) start = time.Now() diff --git a/pkg/services/alerting/notifier_test.go b/pkg/services/alerting/notifier_test.go index 27712789c4f..e885365864b 100644 --- a/pkg/services/alerting/notifier_test.go +++ b/pkg/services/alerting/notifier_test.go @@ -39,13 +39,13 @@ func TestNotificationService(t *testing.T) { require.Truef(t, evalCtx.Ctx.Value(notificationSent{}).(bool), "expected notification to be sent, but wasn't") }) - notificationServiceScenario(t, "Given alert rule with upload image enabled but no renderer available should not render and upload image, but send notification", evalCtx, true, func(scenarioCtx *scenarioContext) { + notificationServiceScenario(t, "Given alert rule with upload image enabled but no renderer available should render and upload unavailable image and send notification", evalCtx, true, func(scenarioCtx *scenarioContext) { scenarioCtx.rendererAvailable = false err := scenarioCtx.notificationService.SendIfNeeded(evalCtx) require.NoError(t, err) - require.Equalf(t, 0, scenarioCtx.renderCount, "expected render to not be called, but it was") - require.Equalf(t, 0, scenarioCtx.imageUploadCount, "expected image to not be uploaded, but it was") + require.Equalf(t, 1, scenarioCtx.renderCount, "expected render to be called, but it wasn't") + require.Equalf(t, 1, scenarioCtx.imageUploadCount, "expected image to be uploaded, but it wasn't") require.Truef(t, evalCtx.Ctx.Value(notificationSent{}).(bool), "expected notification to be sent, but wasn't") }) diff --git a/pkg/services/rendering/rendering.go b/pkg/services/rendering/rendering.go index b00d431228e..04f442104f0 100644 --- a/pkg/services/rendering/rendering.go +++ b/pkg/services/rendering/rendering.go @@ -121,6 +121,14 @@ func (rs *RenderingService) RenderErrorImage(err error) (*RenderResult, error) { }, nil } +func (rs *RenderingService) renderUnavailableImage() *RenderResult { + imgPath := "public/img/rendering_plugin_not_installed.png" + + return &RenderResult{ + FilePath: filepath.Join(setting.HomePath, imgPath), + } +} + func (rs *RenderingService) Render(ctx context.Context, opts Opts) (*RenderResult, error) { if rs.inProgressCount > opts.ConcurrentLimit { return &RenderResult{ @@ -128,8 +136,11 @@ func (rs *RenderingService) Render(ctx context.Context, opts Opts) (*RenderResul }, nil } - if rs.renderAction == nil { - return nil, fmt.Errorf("no renderer found") + if !rs.IsAvailable() { + rs.log.Warn("Could not render image, no image renderer found/installed. " + + "For image rendering support please install the grafana-image-renderer plugin. " + + "Read more at https://grafana.com/docs/grafana/latest/administration/image_rendering/") + return rs.renderUnavailableImage(), nil } rs.log.Info("Rendering", "path", opts.Path) diff --git a/public/img/rendering_plugin_not_installed.png b/public/img/rendering_plugin_not_installed.png index f135ff7cc9f..0445996d40d 100644 Binary files a/public/img/rendering_plugin_not_installed.png and b/public/img/rendering_plugin_not_installed.png differ