From c82e23d96ebfdbcd7897450d4b203b28c556abfa Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Sat, 30 Dec 2017 23:01:51 +0100 Subject: [PATCH] imguploader: Add support for new internal image store (#6922) --- conf/defaults.ini | 7 ++++-- docs/sources/alerting/notifications.md | 6 +++-- pkg/api/http_server.go | 4 ++++ pkg/components/imguploader/imguploader.go | 2 ++ .../imguploader/imguploader_test.go | 18 +++++++++++++++ pkg/components/imguploader/localuploader.go | 22 +++++++++++++++++++ .../imguploader/localuploader_test.go | 18 +++++++++++++++ 7 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 pkg/components/imguploader/localuploader.go create mode 100644 pkg/components/imguploader/localuploader_test.go diff --git a/conf/defaults.ini b/conf/defaults.ini index 4e2929096a6..ccf968df1a3 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -473,8 +473,8 @@ sampler_param = 1 #################################### External Image Storage ############## [external_image_storage] -# You can choose between (s3, webdav, gcs, azure_blob) -provider = +# You can choose between (s3, webdav, gcs, azure_blob, local) +provider = local [external_image_storage.s3] bucket_url = @@ -499,3 +499,6 @@ path = account_name = account_key = container_name = + +[external_image_storage.local] +# does not require any configuration \ No newline at end of file diff --git a/docs/sources/alerting/notifications.md b/docs/sources/alerting/notifications.md index a0673aaea98..8fcdc7e776d 100644 --- a/docs/sources/alerting/notifications.md +++ b/docs/sources/alerting/notifications.md @@ -149,8 +149,10 @@ Prometheus Alertmanager | `prometheus-alertmanager` | no # Enable images in notifications {#external-image-store} -Grafana can render the panel associated with the alert rule and include that in the notification. Most Notification Channels require that this image be publicly accessible (Slack and PagerDuty for example). In order to include images in alert notifications, Grafana can upload the image to an image store. It currently supports -Amazon S3, Webdav, and Azure Blob Storage for this. So to set that up you need to configure the [external image uploader](/installation/configuration/#external-image-storage) in your grafana-server ini config file. +Grafana can render the panel associated with the alert rule and include that in the notification. Most Notification Channels require that this image be publicly accessable (Slack and PagerDuty for example). In order to include images in alert notifications, Grafana can upload the image to an image store. It currently supports +Amazon S3, Webdav, Google Cloud Storage and Azure Blob Storage. So to set that up you need to configure the [external image uploader](/installation/configuration/#external-image-storage) in your grafana-server ini config file. + +By default the local image store is used which allows Grafana to serve the images by itself. Currently only the Email Channels attaches images if no external image store is specified. To include images in alert notifications for other channels then you need to set up an external image store. diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index 0366b9aedad..b911780913d 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -162,6 +162,10 @@ func (hs *HttpServer) newMacaron() *macaron.Macaron { hs.mapStatic(m, setting.StaticRootPath, "", "public") hs.mapStatic(m, setting.StaticRootPath, "robots.txt", "robots.txt") + if setting.ImageUploadProvider == "local" { + hs.mapStatic(m, setting.ImagesDir, "", "/public/img/attachments") + } + m.Use(macaron.Renderer(macaron.RenderOptions{ Directory: path.Join(setting.StaticRootPath, "views"), IndentJSON: macaron.Env != macaron.PROD, diff --git a/pkg/components/imguploader/imguploader.go b/pkg/components/imguploader/imguploader.go index 383d2c6d311..52a31f9f606 100644 --- a/pkg/components/imguploader/imguploader.go +++ b/pkg/components/imguploader/imguploader.go @@ -88,6 +88,8 @@ func NewImageUploader() (ImageUploader, error) { container_name := azureBlobSec.Key("container_name").MustString("") return NewAzureBlobUploader(account_name, account_key, container_name), nil + case "local": + return NewLocalImageUploader() } if setting.ImageUploadProvider != "" { diff --git a/pkg/components/imguploader/imguploader_test.go b/pkg/components/imguploader/imguploader_test.go index d5008c9ae9f..b0311dac975 100644 --- a/pkg/components/imguploader/imguploader_test.go +++ b/pkg/components/imguploader/imguploader_test.go @@ -143,5 +143,23 @@ func TestImageUploaderFactory(t *testing.T) { So(original.container_name, ShouldEqual, "container_name") }) }) + + Convey("Local uploader", func() { + var err error + + setting.NewConfigContext(&setting.CommandLineArgs{ + HomePath: "../../../", + }) + + setting.ImageUploadProvider = "local" + + uploader, err := NewImageUploader() + + So(err, ShouldBeNil) + original, ok := uploader.(*LocalUploader) + + So(ok, ShouldBeTrue) + So(original, ShouldNotBeNil) + }) }) } diff --git a/pkg/components/imguploader/localuploader.go b/pkg/components/imguploader/localuploader.go new file mode 100644 index 00000000000..022d67122a7 --- /dev/null +++ b/pkg/components/imguploader/localuploader.go @@ -0,0 +1,22 @@ +package imguploader + +import ( + "context" + "path" + "path/filepath" + + "github.com/grafana/grafana/pkg/setting" +) + +type LocalUploader struct { +} + +func (u *LocalUploader) Upload(ctx context.Context, imageOnDiskPath string) (string, error) { + filename := filepath.Base(imageOnDiskPath) + image_url := setting.ToAbsUrl(path.Join("public/img/attachments", filename)) + return image_url, nil +} + +func NewLocalImageUploader() (*LocalUploader, error) { + return &LocalUploader{}, nil +} diff --git a/pkg/components/imguploader/localuploader_test.go b/pkg/components/imguploader/localuploader_test.go new file mode 100644 index 00000000000..0d8c0df0e57 --- /dev/null +++ b/pkg/components/imguploader/localuploader_test.go @@ -0,0 +1,18 @@ +package imguploader + +import ( + "context" + "testing" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestUploadToLocal(t *testing.T) { + Convey("[Integration test] for external_image_store.local", t, func() { + localUploader, _ := NewLocalImageUploader() + path, err := localUploader.Upload(context.Background(), "../../../public/img/logo_transparent_400x.png") + + So(err, ShouldBeNil) + So(path, ShouldContainSubstring, "/public/img/attachments") + }) +}