Merge branch 'master' into develop
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
package imguploader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"golang.org/x/oauth2/google"
|
||||
)
|
||||
|
||||
const (
|
||||
tokenUrl string = "https://www.googleapis.com/auth/devstorage.read_write"
|
||||
uploadUrl string = "https://www.googleapis.com/upload/storage/v1/b/%s/o?uploadType=media&name=%s&predefinedAcl=publicRead"
|
||||
)
|
||||
|
||||
type GCSUploader struct {
|
||||
keyFile string
|
||||
bucket string
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func NewGCSUploader(keyFile, bucket string) *GCSUploader {
|
||||
return &GCSUploader{
|
||||
keyFile: keyFile,
|
||||
bucket: bucket,
|
||||
log: log.New("gcsuploader"),
|
||||
}
|
||||
}
|
||||
|
||||
func (u *GCSUploader) Upload(ctx context.Context, imageDiskPath string) (string, error) {
|
||||
key := util.GetRandomString(20) + ".png"
|
||||
|
||||
u.log.Debug("Opening key file ", u.keyFile)
|
||||
data, err := ioutil.ReadFile(u.keyFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
u.log.Debug("Creating JWT conf")
|
||||
conf, err := google.JWTConfigFromJSON(data, tokenUrl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
u.log.Debug("Creating HTTP client")
|
||||
client := conf.Client(ctx)
|
||||
err = u.uploadFile(client, imageDiskPath, key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("https://storage.googleapis.com/%s/%s", u.bucket, key), nil
|
||||
}
|
||||
|
||||
func (u *GCSUploader) uploadFile(client *http.Client, imageDiskPath, key string) error {
|
||||
u.log.Debug("Opening image file ", imageDiskPath)
|
||||
|
||||
fileReader, err := os.Open(imageDiskPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reqUrl := fmt.Sprintf(uploadUrl, u.bucket, key)
|
||||
u.log.Debug("Request URL: ", reqUrl)
|
||||
|
||||
req, err := http.NewRequest("POST", reqUrl, fileReader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "image/png")
|
||||
u.log.Debug("Sending POST request to GCS")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("GCS response status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package imguploader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestUploadToGCS(t *testing.T) {
|
||||
SkipConvey("[Integration test] for external_image_store.gcs", t, func() {
|
||||
setting.NewConfigContext(&setting.CommandLineArgs{
|
||||
HomePath: "../../../",
|
||||
})
|
||||
|
||||
gcsUploader, _ := NewImageUploader()
|
||||
|
||||
path, err := gcsUploader.Upload(context.Background(), "../../../public/img/logo_transparent_400x.png")
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(path, ShouldNotEqual, "")
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package imguploader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
@@ -8,13 +9,13 @@ import (
|
||||
)
|
||||
|
||||
type ImageUploader interface {
|
||||
Upload(path string) (string, error)
|
||||
Upload(ctx context.Context, path string) (string, error)
|
||||
}
|
||||
|
||||
type NopImageUploader struct {
|
||||
}
|
||||
|
||||
func (NopImageUploader) Upload(path string) (string, error) {
|
||||
func (NopImageUploader) Upload(ctx context.Context, path string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
@@ -52,6 +53,16 @@ func NewImageUploader() (ImageUploader, error) {
|
||||
password := webdavSec.Key("password").String()
|
||||
|
||||
return NewWebdavImageUploader(url, username, password, public_url)
|
||||
case "gcs":
|
||||
gcssec, err := setting.Cfg.GetSection("external_image_storage.gcs")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyFile := gcssec.Key("key_file").MustString("")
|
||||
bucketName := gcssec.Key("bucket").MustString("")
|
||||
|
||||
return NewGCSUploader(keyFile, bucketName), nil
|
||||
}
|
||||
|
||||
return NopImageUploader{}, nil
|
||||
|
||||
@@ -96,5 +96,28 @@ func TestImageUploaderFactory(t *testing.T) {
|
||||
So(original.username, ShouldEqual, "username")
|
||||
So(original.password, ShouldEqual, "password")
|
||||
})
|
||||
|
||||
Convey("GCS uploader", func() {
|
||||
var err error
|
||||
|
||||
setting.NewConfigContext(&setting.CommandLineArgs{
|
||||
HomePath: "../../../",
|
||||
})
|
||||
|
||||
setting.ImageUploadProvider = "gcs"
|
||||
|
||||
gcpSec, err := setting.Cfg.GetSection("external_image_storage.gcs")
|
||||
gcpSec.NewKey("key_file", "/etc/secrets/project-79a52befa3f6.json")
|
||||
gcpSec.NewKey("bucket", "project-grafana-east")
|
||||
|
||||
uploader, err := NewImageUploader()
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
original, ok := uploader.(*GCSUploader)
|
||||
|
||||
So(ok, ShouldBeTrue)
|
||||
So(original.keyFile, ShouldEqual, "/etc/secrets/project-79a52befa3f6.json")
|
||||
So(original.bucket, ShouldEqual, "project-grafana-east")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package imguploader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@@ -34,7 +35,7 @@ func NewS3Uploader(region, bucket, acl, accessKey, secretKey string) *S3Uploader
|
||||
}
|
||||
}
|
||||
|
||||
func (u *S3Uploader) Upload(imageDiskPath string) (string, error) {
|
||||
func (u *S3Uploader) Upload(ctx context.Context, imageDiskPath string) (string, error) {
|
||||
sess, err := session.NewSession()
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package imguploader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -15,7 +16,7 @@ func TestUploadToS3(t *testing.T) {
|
||||
|
||||
s3Uploader, _ := NewImageUploader()
|
||||
|
||||
path, err := s3Uploader.Upload("../../../public/img/logo_transparent_400x.png")
|
||||
path, err := s3Uploader.Upload(context.Background(), "../../../public/img/logo_transparent_400x.png")
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(path, ShouldNotEqual, "")
|
||||
|
||||
@@ -2,6 +2,7 @@ package imguploader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
@@ -33,7 +34,7 @@ var netClient = &http.Client{
|
||||
Transport: netTransport,
|
||||
}
|
||||
|
||||
func (u *WebdavUploader) Upload(pa string) (string, error) {
|
||||
func (u *WebdavUploader) Upload(ctx context.Context, pa string) (string, error) {
|
||||
url, _ := url.Parse(u.url)
|
||||
filename := util.GetRandomString(20) + ".png"
|
||||
url.Path = path.Join(url.Path, filename)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package imguploader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
@@ -11,7 +12,7 @@ func TestUploadToWebdav(t *testing.T) {
|
||||
// Can be tested with this docker container: https://hub.docker.com/r/morrisjobke/webdav/
|
||||
SkipConvey("[Integration test] for external_image_store.webdav", t, func() {
|
||||
webdavUploader, _ := NewWebdavImageUploader("http://localhost:8888/webdav/", "test", "test", "")
|
||||
path, err := webdavUploader.Upload("../../../public/img/logo_transparent_400x.png")
|
||||
path, err := webdavUploader.Upload(context.Background(), "../../../public/img/logo_transparent_400x.png")
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(path, ShouldStartWith, "http://localhost:8888/webdav/")
|
||||
@@ -19,7 +20,7 @@ func TestUploadToWebdav(t *testing.T) {
|
||||
|
||||
SkipConvey("[Integration test] for external_image_store.webdav with public url", t, func() {
|
||||
webdavUploader, _ := NewWebdavImageUploader("http://localhost:8888/webdav/", "test", "test", "http://publicurl:8888/webdav")
|
||||
path, err := webdavUploader.Upload("../../../public/img/logo_transparent_400x.png")
|
||||
path, err := webdavUploader.Upload(context.Background(), "../../../public/img/logo_transparent_400x.png")
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(path, ShouldStartWith, "http://publicurl:8888/webdav/")
|
||||
|
||||
Reference in New Issue
Block a user