ImgUploader: add support for non-amazon S3 (#20354)

* imguploader: add support for non-Amazon S3 endpoints and forcing of path-style S3 addressing

fixes #11240

Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
Paul Emmerich
2020-01-02 15:10:20 +01:00
committed by Arve Knudsen
parent 85072b78a4
commit 42032f6c03
20 changed files with 2901 additions and 33 deletions

View File

@@ -35,6 +35,8 @@ func NewImageUploader() (ImageUploader, error) {
return nil, err
}
endpoint := s3sec.Key("endpoint").MustString("")
pathStyleAccess := s3sec.Key("path_style_access").MustBool(false)
bucket := s3sec.Key("bucket").MustString("")
region := s3sec.Key("region").MustString("")
path := s3sec.Key("path").MustString("")
@@ -55,7 +57,7 @@ func NewImageUploader() (ImageUploader, error) {
region = info.region
}
return NewS3Uploader(region, bucket, path, "public-read", accessKey, secretKey), nil
return NewS3Uploader(endpoint, region, bucket, path, "public-read", accessKey, secretKey, pathStyleAccess), nil
case "webdav":
webdavSec, err := setting.Raw.GetSection("external_image_storage.webdav")
if err != nil {

View File

@@ -12,32 +12,35 @@ import (
"github.com/aws/aws-sdk-go/aws/credentials/endpointcreds"
"github.com/aws/aws-sdk-go/aws/defaults"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/util"
)
type S3Uploader struct {
region string
bucket string
path string
acl string
secretKey string
accessKey string
log log.Logger
endpoint string
region string
bucket string
path string
acl string
secretKey string
accessKey string
pathStyleAccess bool
log log.Logger
}
func NewS3Uploader(region, bucket, path, acl, accessKey, secretKey string) *S3Uploader {
func NewS3Uploader(endpoint, region, bucket, path, acl, accessKey, secretKey string, pathStyleAccess bool) *S3Uploader {
return &S3Uploader{
region: region,
bucket: bucket,
path: path,
acl: acl,
accessKey: accessKey,
secretKey: secretKey,
log: log.New("s3uploader"),
endpoint: endpoint,
region: region,
bucket: bucket,
path: path,
acl: acl,
accessKey: accessKey,
secretKey: secretKey,
pathStyleAccess: pathStyleAccess,
log: log.New("s3uploader"),
}
}
@@ -56,18 +59,18 @@ func (u *S3Uploader) Upload(ctx context.Context, imageDiskPath string) (string,
remoteCredProvider(sess),
})
cfg := &aws.Config{
Region: aws.String(u.region),
Credentials: creds,
Region: aws.String(u.region),
Endpoint: aws.String(u.endpoint),
S3ForcePathStyle: aws.Bool(u.pathStyleAccess),
Credentials: creds,
}
s3_endpoint, _ := endpoints.DefaultResolver().EndpointFor("s3", u.region)
rand, err := util.GetRandomString(20)
if err != nil {
return "", err
}
key := u.path + rand + pngExt
image_url := s3_endpoint.URL + "/" + u.bucket + "/" + key
log.Debug("Uploading image to s3. url = %s", image_url)
log.Debug("Uploading image to s3. bucket = %s, path = %s", u.bucket, key)
file, err := os.Open(imageDiskPath)
if err != nil {
@@ -79,19 +82,18 @@ func (u *S3Uploader) Upload(ctx context.Context, imageDiskPath string) (string,
if err != nil {
return "", err
}
svc := s3.New(sess, cfg)
params := &s3.PutObjectInput{
uploader := s3manager.NewUploader(sess)
result, err := uploader.Upload(&s3manager.UploadInput{
Bucket: aws.String(u.bucket),
Key: aws.String(key),
ACL: aws.String(u.acl),
Body: file,
ContentType: aws.String("image/png"),
}
_, err = svc.PutObject(params)
})
if err != nil {
return "", err
}
return image_url, nil
return result.Location, nil
}
func remoteCredProvider(sess *session.Session) credentials.Provider {