GCS support via JSON API
This commit is contained in:
committed by
bergquist
parent
1188f8df73
commit
fcdf282090
@@ -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, "")
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user