Adds StorageDriverFactory, unifying creation of StorageDrivers

Custom storage drivers can register a factory to create the driver by
name, similar to the database/sql package's Register and Open
factory.Create returns an in-process driver if registered or an IPC
driver if one can be found, erroring otherwise
This standardizes parameter passing for creation of storage drivers

Also adds documentation for storagedriver package and children
This commit is contained in:
Brian Bland 2014-10-28 18:15:40 -07:00
parent ff81f3a719
commit ca0084fad1
15 changed files with 290 additions and 79 deletions

View file

@ -2,6 +2,7 @@ package s3
import (
"bytes"
"fmt"
"io"
"net/http"
"strconv"
@ -9,21 +10,82 @@ import (
"github.com/crowdmob/goamz/aws"
"github.com/crowdmob/goamz/s3"
"github.com/docker/docker-registry/storagedriver"
"github.com/docker/docker-registry/storagedriver/factory"
)
/* Chunks need to be at least 5MB to store with a multipart upload on S3 */
const DriverName = "s3"
// Chunks need to be at least 5MB to store with a multipart upload on S3
const minChunkSize = uint64(5 * 1024 * 1024)
/* The largest amount of parts you can request from S3 */
// The largest amount of parts you can request from S3
const listPartsMax = 1000
func init() {
factory.Register(DriverName, &s3DriverFactory{})
}
// Implements the factory.StorageDriverFactory interface
type s3DriverFactory struct{}
func (factory *s3DriverFactory) Create(parameters map[string]string) (storagedriver.StorageDriver, error) {
return FromParameters(parameters)
}
// Storage Driver backed by Amazon S3
// Objects are stored at absolute keys in the provided bucket
type S3Driver struct {
S3 *s3.S3
Bucket *s3.Bucket
Encrypt bool
}
func NewDriver(accessKey string, secretKey string, region aws.Region, encrypt bool, bucketName string) (*S3Driver, error) {
// Constructs a new S3Driver with a given parameters map
// Required parameters:
// - accesskey
// - secretkey
// - region
// - bucket
// - encrypt
func FromParameters(parameters map[string]string) (*S3Driver, error) {
accessKey, ok := parameters["accesskey"]
if !ok || accessKey == "" {
return nil, fmt.Errorf("No accesskey parameter provided")
}
secretKey, ok := parameters["secretkey"]
if !ok || secretKey == "" {
return nil, fmt.Errorf("No secretkey parameter provided")
}
regionName, ok := parameters["region"]
if !ok || regionName == "" {
return nil, fmt.Errorf("No region parameter provided")
}
region := aws.GetRegion(regionName)
if region.Name == "" {
return nil, fmt.Errorf("Invalid region provided: %s", region)
}
bucket, ok := parameters["bucket"]
if !ok || bucket == "" {
return nil, fmt.Errorf("No bucket parameter provided")
}
encrypt, ok := parameters["encrypt"]
if !ok {
return nil, fmt.Errorf("No encrypt parameter provided")
}
encryptBool, err := strconv.ParseBool(encrypt)
if err != nil {
return nil, fmt.Errorf("Unable to parse the encrypt parameter: %v", err)
}
return New(accessKey, secretKey, region, encryptBool, bucket)
}
// Constructs a new S3Driver with the given AWS credentials, region, encryption flag, and bucketName
func New(accessKey string, secretKey string, region aws.Region, encrypt bool, bucketName string) (*S3Driver, error) {
auth := aws.Auth{AccessKey: accessKey, SecretKey: secretKey}
s3obj := s3.New(auth, region)
bucket := s3obj.Bucket(bucketName)

View file

@ -2,6 +2,7 @@ package s3
import (
"os"
"strconv"
"testing"
"github.com/crowdmob/goamz/aws"
@ -14,23 +15,34 @@ import (
func Test(t *testing.T) { TestingT(t) }
func init() {
accessKey := os.Getenv("ACCESS_KEY")
secretKey := os.Getenv("SECRET_KEY")
accessKey := os.Getenv("AWS_ACCESS_KEY")
secretKey := os.Getenv("AWS_SECRET_KEY")
region := os.Getenv("AWS_REGION")
bucket := os.Getenv("S3_BUCKET")
encrypt := os.Getenv("S3_ENCRYPT")
s3DriverConstructor := func() (storagedriver.StorageDriver, error) {
return NewDriver(accessKey, secretKey, aws.GetRegion(region), true, bucket)
shouldEncrypt, err := strconv.ParseBool(encrypt)
if err != nil {
return nil, err
}
return New(accessKey, secretKey, aws.GetRegion(region), shouldEncrypt, bucket)
}
// Skip S3 storage driver tests if environment variable parameters are not provided
skipCheck := func() string {
if accessKey == "" || secretKey == "" || region == "" || bucket == "" || encrypt == "" {
return "Must set ACCESS_KEY, SECRET_KEY, AWS_REGION, S3_BUCKET, and S3_ENCRYPT to run S3 tests"
return "Must set AWS_ACCESS_KEY, AWS_SECRET_KEY, AWS_REGION, S3_BUCKET, and S3_ENCRYPT to run S3 tests"
}
return ""
}
testsuites.RegisterInProcessSuite(s3DriverConstructor, skipCheck)
testsuites.RegisterIPCSuite("s3", map[string]string{"accessKey": accessKey, "secretKey": secretKey, "region": region, "bucket": bucket, "encrypt": encrypt}, skipCheck)
testsuites.RegisterIPCSuite(DriverName, map[string]string{
"accesskey": accessKey,
"secretkey": secretKey,
"region": region,
"bucket": bucket,
"encrypt": encrypt,
}, skipCheck)
}