expose s3 endpoint as flag (#87)

Exposes the s3 endpoint option as a cli flag and storage config
property.  Uses the kopia default s3.amazonaws.com as a fallback.
This commit is contained in:
Keepers 2022-05-27 09:11:26 -06:00 committed by GitHub
parent e6663fd0f1
commit d923c4072b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 23 additions and 5 deletions

3
.gitignore vendored
View File

@ -13,3 +13,6 @@
# Dependency directories (remove the comment below to include it) # Dependency directories (remove the comment below to include it)
# vendor/ # vendor/
# IDE
.vscode

View File

@ -12,8 +12,9 @@ import (
// s3 bucket info from flags // s3 bucket info from flags
var ( var (
bucket string
accessKey string accessKey string
bucket string
endpoint string
) )
// called by repo.go to map parent subcommands to provider-specific handling. // called by repo.go to map parent subcommands to provider-specific handling.
@ -27,9 +28,10 @@ func addS3Commands(parent *cobra.Command) *cobra.Command {
} }
parent.AddCommand(c) parent.AddCommand(c)
fs := c.Flags() fs := c.Flags()
fs.StringVar(&accessKey, "access-key", "", "Access key ID (replaces the AWS_ACCESS_KEY_ID env variable).")
fs.StringVar(&bucket, "bucket", "", "Name of the S3 bucket (required).") fs.StringVar(&bucket, "bucket", "", "Name of the S3 bucket (required).")
c.MarkFlagRequired("bucket") c.MarkFlagRequired("bucket")
fs.StringVar(&accessKey, "access-key", "", "Access key ID (replaces the AWS_ACCESS_KEY_ID env variable).") fs.StringVar(&endpoint, "endpoint", "s3.amazonaws.com", "Server endpoint for S3 communication.")
return c return c
} }
@ -116,6 +118,7 @@ func makeS3Config() storage.S3Config {
return storage.S3Config{ return storage.S3Config{
AccessKey: ak, AccessKey: ak,
Bucket: bucket, Bucket: bucket,
Endpoint: endpoint,
SecretKey: os.Getenv("AWS_SECRET_ACCESS_KEY"), SecretKey: os.Getenv("AWS_SECRET_ACCESS_KEY"),
SessionToken: os.Getenv("AWS_SESSION_TOKEN"), SessionToken: os.Getenv("AWS_SESSION_TOKEN"),
} }

View File

@ -14,10 +14,14 @@ const (
) )
func s3BlobStorage(ctx context.Context, cfg storage.S3Config) (blob.Storage, error) { func s3BlobStorage(ctx context.Context, cfg storage.S3Config) (blob.Storage, error) {
endpoint := defaultS3Endpoint
if len(cfg.Endpoint) > 0 {
endpoint = cfg.Endpoint
}
opts := s3.Options{ opts := s3.Options{
AccessKeyID: cfg.AccessKey, AccessKeyID: cfg.AccessKey,
BucketName: cfg.Bucket, BucketName: cfg.Bucket,
Endpoint: defaultS3Endpoint, Endpoint: endpoint,
SecretAccessKey: cfg.SecretKey, SecretAccessKey: cfg.SecretKey,
SessionToken: cfg.SessionToken, SessionToken: cfg.SessionToken,
} }

View File

@ -3,6 +3,7 @@ package storage
type S3Config struct { type S3Config struct {
AccessKey string AccessKey string
Bucket string Bucket string
Endpoint string
SecretKey string SecretKey string
SessionToken string SessionToken string
} }
@ -10,6 +11,7 @@ type S3Config struct {
const ( const (
keyS3AccessKey = "s3_accessKey" keyS3AccessKey = "s3_accessKey"
keyS3Bucket = "s3_bucket" keyS3Bucket = "s3_bucket"
keyS3Endpoint = "s3_endpoint"
keyS3SecretKey = "s3_secretKey" keyS3SecretKey = "s3_secretKey"
keyS3SessionToken = "s3_sessionToken" keyS3SessionToken = "s3_sessionToken"
) )
@ -18,6 +20,7 @@ func (c S3Config) Config() config {
return config{ return config{
keyS3AccessKey: c.AccessKey, keyS3AccessKey: c.AccessKey,
keyS3Bucket: c.Bucket, keyS3Bucket: c.Bucket,
keyS3Endpoint: c.Endpoint,
keyS3SecretKey: c.SecretKey, keyS3SecretKey: c.SecretKey,
keyS3SessionToken: c.SessionToken, keyS3SessionToken: c.SessionToken,
} }
@ -29,6 +32,7 @@ func (s Storage) S3Config() S3Config {
if len(s.Config) > 0 { if len(s.Config) > 0 {
c.AccessKey = s.Config[keyS3AccessKey].(string) c.AccessKey = s.Config[keyS3AccessKey].(string)
c.Bucket = s.Config[keyS3Bucket].(string) c.Bucket = s.Config[keyS3Bucket].(string)
c.Endpoint = s.Config[keyS3Endpoint].(string)
c.SecretKey = s.Config[keyS3SecretKey].(string) c.SecretKey = s.Config[keyS3SecretKey].(string)
c.SessionToken = s.Config[keyS3SessionToken].(string) c.SessionToken = s.Config[keyS3SessionToken].(string)
} }

View File

@ -7,7 +7,7 @@ import (
) )
func TestS3Config_Config(t *testing.T) { func TestS3Config_Config(t *testing.T) {
s3 := storage.S3Config{"bkt", "ak", "sk", "tkn"} s3 := storage.S3Config{"ak", "bkt", "end", "sk", "tkn"}
c := s3.Config() c := s3.Config()
table := []struct { table := []struct {
key string key string
@ -15,6 +15,7 @@ func TestS3Config_Config(t *testing.T) {
}{ }{
{"s3_bucket", s3.Bucket}, {"s3_bucket", s3.Bucket},
{"s3_accessKey", s3.AccessKey}, {"s3_accessKey", s3.AccessKey},
{"s3_endpoint", s3.Endpoint},
{"s3_secretKey", s3.SecretKey}, {"s3_secretKey", s3.SecretKey},
{"s3_sessionToken", s3.SessionToken}, {"s3_sessionToken", s3.SessionToken},
} }
@ -28,7 +29,7 @@ func TestS3Config_Config(t *testing.T) {
} }
func TestStorage_S3Config(t *testing.T) { func TestStorage_S3Config(t *testing.T) {
in := storage.S3Config{"bkt", "ak", "sk", "tkn"} in := storage.S3Config{"ak", "bkt", "end", "sk", "tkn"}
s := storage.NewStorage(storage.ProviderS3, in) s := storage.NewStorage(storage.ProviderS3, in)
out := s.S3Config() out := s.S3Config()
if in.Bucket != out.Bucket { if in.Bucket != out.Bucket {
@ -37,6 +38,9 @@ func TestStorage_S3Config(t *testing.T) {
if in.AccessKey != out.AccessKey { if in.AccessKey != out.AccessKey {
t.Errorf("expected S3Config.AccessKey to be [%s], got [%s]", in.AccessKey, out.AccessKey) t.Errorf("expected S3Config.AccessKey to be [%s], got [%s]", in.AccessKey, out.AccessKey)
} }
if in.Endpoint != out.Endpoint {
t.Errorf("expected S3Config.Endpoint to be [%s], got [%s]", in.Endpoint, out.Endpoint)
}
if in.SecretKey != out.SecretKey { if in.SecretKey != out.SecretKey {
t.Errorf("expected S3Config.SecretKey to be [%s], got [%s]", in.SecretKey, out.SecretKey) t.Errorf("expected S3Config.SecretKey to be [%s], got [%s]", in.SecretKey, out.SecretKey)
} }