Skip to content

Commit 79dcec7

Browse files
author
Juan Rodriguez Hortala
authored
S3: Support specifying S3 storage class (thanos-io#25)
Enable specifying S3 storage class Allow specifying a storage class for S3 object storage in config.put_user_metadata:X-Amz-Storage-Class. If not specified then STANDARD is used by default. Solves: thanos-io/thanos#5663 Signed-off-by: Juan Rodriguez Hortala <[email protected]> Signed-off-by: Juan Rodriguez Hortala <[email protected]>
1 parent cec51c6 commit 79dcec7

File tree

3 files changed

+46
-0
lines changed

3 files changed

+46
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ We use *breaking :warning:* to mark changes that are not backward compatible (re
1414

1515
### Added
1616
- [#15](https://github.com/thanos-io/objstore/pull/15) Add Oracle Cloud Infrastructure Object Storage Bucket support.
17+
- [#25](https://github.com/thanos-io/objstore/pull/25) S3: Support specifying S3 storage class.
1718

1819
### Changed
1920

providers/s3/s3.go

+16
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ const (
9696
// NOTE: we're using a context value only because it's a very specific S3 option. If SSE will
9797
// be available to wider set of backends we should probably add a variadic option to Get() and Upload().
9898
sseConfigKey = ctxKey(0)
99+
100+
// Storage class header.
101+
amzStorageClass = "X-Amz-Storage-Class"
99102
)
100103

101104
var DefaultConfig = Config{
@@ -160,6 +163,7 @@ type Bucket struct {
160163
client *minio.Client
161164
defaultSSE encrypt.ServerSide
162165
putUserMetadata map[string]string
166+
storageClass string
163167
partSize uint64
164168
listObjectsV1 bool
165169
}
@@ -310,12 +314,23 @@ func NewBucketWithConfig(logger log.Logger, config Config, component string) (*B
310314
return nil, errors.Errorf("Initialize s3 client list objects version: Unsupported version %q was provided. Supported values are v1, v2", config.ListObjectsVersion)
311315
}
312316

317+
var storageClass string
318+
amzStorageClassLower := strings.ToLower(amzStorageClass)
319+
for k, v := range config.PutUserMetadata {
320+
if strings.ToLower(k) == amzStorageClassLower {
321+
delete(config.PutUserMetadata, k)
322+
storageClass = v
323+
break
324+
}
325+
}
326+
313327
bkt := &Bucket{
314328
logger: logger,
315329
name: config.Bucket,
316330
client: client,
317331
defaultSSE: sse,
318332
putUserMetadata: config.PutUserMetadata,
333+
storageClass: storageClass,
319334
partSize: config.PartSize,
320335
listObjectsV1: config.ListObjectsVersion == "v1",
321336
}
@@ -486,6 +501,7 @@ func (b *Bucket) Upload(ctx context.Context, name string, r io.Reader) error {
486501
PartSize: partSize,
487502
ServerSideEncryption: sse,
488503
UserMetadata: b.putUserMetadata,
504+
StorageClass: b.storageClass,
489505
// 4 is what minio-go have as the default. To be certain we do micro benchmark before any changes we
490506
// ensure we pin this number to four.
491507
// TODO(bwplotka): Consider adjusting this number to GOMAXPROCS or to expose this in config if it becomes bottleneck.

providers/s3/s3_test.go

+29
Original file line numberDiff line numberDiff line change
@@ -419,3 +419,32 @@ func TestBucket_Get_ShouldReturnErrorIfServerTruncateResponse(t *testing.T) {
419419
_, err = ioutil.ReadAll(reader)
420420
testutil.Equals(t, io.ErrUnexpectedEOF, err)
421421
}
422+
423+
func TestParseConfig_CustomStorageClass(t *testing.T) {
424+
for _, testCase := range []struct{
425+
name, storageClassKey string
426+
}{
427+
{ name: "ProperCase", storageClassKey: "X-Amz-Storage-Class" },
428+
{ name: "UpperCase", storageClassKey: "X-AMZ-STORAGE-CLASS" },
429+
{ name: "LowerCase", storageClassKey: "x-amz-storage-class" },
430+
{ name: "MixedCase", storageClassKey: "X-Amz-sToraGe-Class" },
431+
}{
432+
t.Run(testCase.name, func(t *testing.T) {
433+
cfg := DefaultConfig
434+
cfg.Endpoint = endpoint
435+
storageClass := "STANDARD_IA"
436+
cfg.PutUserMetadata[testCase.storageClassKey] = storageClass
437+
bkt, err := NewBucketWithConfig(log.NewNopLogger(), cfg, "test")
438+
testutil.Ok(t, err)
439+
testutil.Equals(t, storageClass, bkt.storageClass)
440+
})
441+
}
442+
}
443+
444+
func TestParseConfig_DefaultStorageClassIsZero(t *testing.T) {
445+
cfg := DefaultConfig
446+
cfg.Endpoint = endpoint
447+
bkt, err := NewBucketWithConfig(log.NewNopLogger(), cfg, "test")
448+
testutil.Ok(t, err)
449+
testutil.Equals(t, "", bkt.storageClass)
450+
}

0 commit comments

Comments
 (0)