GCS support via JSON API

This commit is contained in:
Konstantin Chukhlomin
2017-09-15 16:11:02 +02:00
committed by bergquist
parent 1188f8df73
commit fcdf282090
18 changed files with 1571 additions and 68 deletions
+62 -22
View File
@@ -1,56 +1,96 @@
package imguploader
import (
"cloud.google.com/go/storage"
"context"
"errors"
"fmt"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/util"
"golang.org/x/net/context"
"google.golang.org/api/option"
"golang.org/x/oauth2/google"
"io/ioutil"
"net/http"
"os"
)
type GCPUploader struct {
type GCSUploader struct {
keyFile string
bucket string
log log.Logger
}
func NewGCPUploader(keyFile, bucket string) *GCPUploader {
return &GCPUploader{
func NewGCSUploader(keyFile, bucket string) *GCSUploader {
return &GCSUploader{
keyFile: keyFile,
bucket: bucket,
log: log.New("gcpuploader"),
log: log.New("gcsuploader"),
}
}
func (u *GCPUploader) Upload(imageDiskPath string) (string, error) {
ctx := context.Background()
client, err := storage.NewClient(ctx, option.WithServiceAccountFile(u.keyFile))
if err != nil {
return "", err
}
func (u *GCSUploader) Upload(imageDiskPath string) (string, error) {
key := util.GetRandomString(20) + ".png"
log.Debug("Uploading image to GCP bucket = %s key = %s", u.bucket, key)
file, err := ioutil.ReadFile(imageDiskPath)
log.Debug("Opening key file ", u.keyFile)
ctx := context.Background()
data, err := ioutil.ReadFile(u.keyFile)
if err != nil {
return "", err
}
wc := client.Bucket(u.bucket).Object(key).NewWriter(ctx)
wc.ContentType = "image/png"
wc.ACL = []storage.ACLRule{{Entity: storage.AllUsers, Role: storage.RoleReader}}
log.Debug("Creating JWT conf")
if _, err := wc.Write(file); err != nil {
conf, err := google.JWTConfigFromJSON(data, "https://www.googleapis.com/auth/devstorage.full_control")
if err != nil {
return "", err
}
if err := wc.Close(); err != nil {
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 {
log.Debug("Opening image file ", imageDiskPath)
fileReader, err := os.Open(imageDiskPath)
if err != nil {
return err
}
reqUrl := fmt.Sprintf(
"https://www.googleapis.com/upload/storage/v1/b/%s/o?uploadType=media&name=%s&predefinedAcl=publicRead",
u.bucket,
key,
)
log.Debug("Request URL: ", reqUrl)
req, err := http.NewRequest("POST", reqUrl, fileReader)
if err != nil {
return err
}
req.Header.Add("Content-Type", "image/png")
log.Debug("Sending POST request to GCS")
resp, err := client.Do(req)
if err != nil {
return err
}
log.Debug("GCS API response header", resp.Header)
if resp.StatusCode != 200 {
return errors.New(fmt.Sprintf("GCS response status code %d", resp.StatusCode))
}
return nil
}
@@ -7,15 +7,15 @@ import (
. "github.com/smartystreets/goconvey/convey"
)
func TestUploadToGCP(t *testing.T) {
SkipConvey("[Integration test] for external_image_store.gcp", t, func() {
func TestUploadToGCS(t *testing.T) {
SkipConvey("[Integration test] for external_image_store.gcs", t, func() {
setting.NewConfigContext(&setting.CommandLineArgs{
HomePath: "../../../",
})
gcpUploader, _ := NewImageUploader()
gcsUploader, _ := NewImageUploader()
path, err := gcpUploader.Upload("../../../public/img/logo_transparent_400x.png")
path, err := gcsUploader.Upload("../../../public/img/logo_transparent_400x.png")
So(err, ShouldBeNil)
So(path, ShouldNotEqual, "")
+5 -5
View File
@@ -52,16 +52,16 @@ func NewImageUploader() (ImageUploader, error) {
password := webdavSec.Key("password").String()
return NewWebdavImageUploader(url, username, password, public_url)
case "gcp":
gcpsec, err := setting.Cfg.GetSection("external_image_storage.gcp")
case "gcs":
gcssec, err := setting.Cfg.GetSection("external_image_storage.gcs")
if err != nil {
return nil, err
}
keyFile := gcpsec.Key("key_file").MustString("")
bucketName := gcpsec.Key("bucket").MustString("")
keyFile := gcssec.Key("key_file").MustString("")
bucketName := gcssec.Key("bucket").MustString("")
return NewGCPUploader(keyFile, bucketName), nil
return NewGCSUploader(keyFile, bucketName), nil
}
return NopImageUploader{}, nil
@@ -97,23 +97,23 @@ func TestImageUploaderFactory(t *testing.T) {
So(original.password, ShouldEqual, "password")
})
Convey("GCP uploader", func() {
Convey("GCS uploader", func() {
var err error
setting.NewConfigContext(&setting.CommandLineArgs{
HomePath: "../../../",
})
setting.ImageUploadProvider = "gcp"
setting.ImageUploadProvider = "gcs"
gcpSec, err := setting.Cfg.GetSection("external_image_storage.gcp")
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.(*GCPUploader)
original, ok := uploader.(*GCSUploader)
So(ok, ShouldBeTrue)
So(original.keyFile, ShouldEqual, "/etc/secrets/project-79a52befa3f6.json")