Skip to content

Commit dc4b91e

Browse files
committed
Aws cli compatibility improvement
1 parent ca254b9 commit dc4b91e

3 files changed

Lines changed: 108 additions & 12 deletions

File tree

cache-cli/pkg/storage/s3.go

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"github.com/aws/aws-sdk-go-v2/credentials"
1010
"github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds"
1111
"github.com/aws/aws-sdk-go-v2/service/s3"
12+
"github.com/aws/smithy-go/middleware"
13+
smithyhttp "github.com/aws/smithy-go/transport/http"
1214
log "github.com/sirupsen/logrus"
1315
)
1416

@@ -26,6 +28,30 @@ type S3StorageOptions struct {
2628
Config StorageConfig
2729
}
2830

31+
type removeS3OperationIDMiddleware struct{}
32+
33+
func (m *removeS3OperationIDMiddleware) ID() string {
34+
return "RemoveS3OperationIDMiddleware"
35+
}
36+
37+
func (m *removeS3OperationIDMiddleware) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) (
38+
out middleware.BuildOutput,
39+
metadata middleware.Metadata,
40+
err error,
41+
) {
42+
if request, ok := in.Request.(*smithyhttp.Request); ok {
43+
query := request.URL.Query()
44+
query.Del("x-id")
45+
request.URL.RawQuery = query.Encode()
46+
}
47+
48+
return next.HandleBuild(ctx, in)
49+
}
50+
51+
func removeS3OperationID(stack *middleware.Stack) error {
52+
return stack.Build.Add(&removeS3OperationIDMiddleware{}, middleware.After)
53+
}
54+
2955
func NewS3Storage(options S3StorageOptions) (*S3Storage, error) {
3056
if options.URL != "" {
3157
return createS3StorageUsingEndpoint(options.Bucket, options.Project, options.URL, options.Config)
@@ -52,7 +78,9 @@ func createDefaultS3Storage(s3Bucket, project string, storageConfig StorageConfi
5278
}
5379

5480
return &S3Storage{
55-
Client: s3.NewFromConfig(config),
81+
Client: s3.NewFromConfig(config, func(o *s3.Options) {
82+
o.APIOptions = append(o.APIOptions, removeS3OperationID)
83+
}),
5684
Bucket: s3Bucket,
5785
Project: project,
5886
StorageConfig: storageConfig,
@@ -69,7 +97,9 @@ func createDefaultS3Storage(s3Bucket, project string, storageConfig StorageConfi
6997
}
7098

7199
return &S3Storage{
72-
Client: s3.NewFromConfig(config),
100+
Client: s3.NewFromConfig(config, func(o *s3.Options) {
101+
o.APIOptions = append(o.APIOptions, removeS3OperationID)
102+
}),
73103
Bucket: s3Bucket,
74104
Project: project,
75105
StorageConfig: storageConfig,
@@ -83,20 +113,28 @@ func createDefaultS3Storage(s3Bucket, project string, storageConfig StorageConfi
83113
}
84114

85115
return &S3Storage{
86-
Client: s3.NewFromConfig(config),
116+
Client: s3.NewFromConfig(config, func(o *s3.Options) {
117+
o.APIOptions = append(o.APIOptions, removeS3OperationID)
118+
}),
87119
Bucket: s3Bucket,
88120
Project: project,
89121
StorageConfig: storageConfig,
90122
}, nil
91123
}
92124

93125
func createS3StorageUsingEndpoint(s3Bucket, project, s3Url string, storageConfig StorageConfig) (*S3Storage, error) {
126+
region := os.Getenv("SEMAPHORE_CACHE_S3_REGION")
127+
if region == "" {
128+
region = "auto"
129+
}
130+
94131
options := []func(*awsConfig.LoadOptions) error{
95-
awsConfig.WithRegion("auto"),
132+
awsConfig.WithRegion(region),
96133
awsConfig.WithEndpointResolverWithOptions(
97134
aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
98135
return aws.Endpoint{
99-
URL: s3Url,
136+
URL: s3Url,
137+
SigningRegion: region,
100138
}, nil
101139
}),
102140
),
@@ -125,6 +163,7 @@ func createS3StorageUsingEndpoint(s3Bucket, project, s3Url string, storageConfig
125163
StorageConfig: storageConfig,
126164
Client: s3.NewFromConfig(cfg, func(o *s3.Options) {
127165
o.UsePathStyle = true
166+
o.APIOptions = append(o.APIOptions, removeS3OperationID)
128167
}),
129168
}, nil
130169
}

cache-cli/pkg/storage/s3_restore.go

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,89 @@ package storage
33
import (
44
"context"
55
"fmt"
6+
"io"
67
"io/ioutil"
78
"os"
89

9-
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
1010
"github.com/aws/aws-sdk-go-v2/service/s3"
1111
)
1212

13+
const defaultS3DownloadPartSize = int64(8 * 1024 * 1024)
14+
1315
func (s *S3Storage) Restore(key string) (*os.File, error) {
1416
tempFile, err := ioutil.TempFile(os.TempDir(), fmt.Sprintf("%s-*", key))
1517
if err != nil {
1618
return nil, err
1719
}
1820

1921
bucketKey := fmt.Sprintf("%s/%s", s.Project, key)
20-
downloader := manager.NewDownloader(s.Client)
21-
_, err = downloader.Download(context.TODO(), tempFile, &s3.GetObjectInput{
22+
headOutput, err := s.Client.HeadObject(context.TODO(), &s3.HeadObjectInput{
2223
Bucket: &s.Bucket,
2324
Key: &bucketKey,
2425
})
25-
2626
if err != nil {
2727
_ = tempFile.Close()
2828
return nil, err
2929
}
3030

31+
// Download in 8 MiB ranges to match aws-cli style segmented GET requests.
32+
if headOutput.ContentLength > 0 {
33+
for start := int64(0); start < headOutput.ContentLength; start += defaultS3DownloadPartSize {
34+
end := start + defaultS3DownloadPartSize - 1
35+
if end >= headOutput.ContentLength {
36+
end = headOutput.ContentLength - 1
37+
}
38+
39+
byteRange := fmt.Sprintf("bytes=%d-%d", start, end)
40+
input := &s3.GetObjectInput{
41+
Bucket: &s.Bucket,
42+
Key: &bucketKey,
43+
Range: &byteRange,
44+
}
45+
if headOutput.ETag != nil {
46+
input.IfMatch = headOutput.ETag
47+
}
48+
49+
output, err := s.Client.GetObject(context.TODO(), input)
50+
if err != nil {
51+
_ = tempFile.Close()
52+
return nil, err
53+
}
54+
55+
_, err = io.Copy(tempFile, output.Body)
56+
closeErr := output.Body.Close()
57+
if err != nil {
58+
_ = tempFile.Close()
59+
return nil, err
60+
}
61+
62+
if closeErr != nil {
63+
_ = tempFile.Close()
64+
return nil, closeErr
65+
}
66+
}
67+
} else {
68+
output, err := s.Client.GetObject(context.TODO(), &s3.GetObjectInput{
69+
Bucket: &s.Bucket,
70+
Key: &bucketKey,
71+
})
72+
if err != nil {
73+
_ = tempFile.Close()
74+
return nil, err
75+
}
76+
77+
_, err = io.Copy(tempFile, output.Body)
78+
closeErr := output.Body.Close()
79+
if err != nil {
80+
_ = tempFile.Close()
81+
return nil, err
82+
}
83+
84+
if closeErr != nil {
85+
_ = tempFile.Close()
86+
return nil, closeErr
87+
}
88+
}
89+
3190
return tempFile, tempFile.Close()
3291
}

cache-cli/pkg/storage/s3_store.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"os"
77

8-
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
98
"github.com/aws/aws-sdk-go-v2/service/s3"
109
log "github.com/sirupsen/logrus"
1110
)
@@ -18,8 +17,7 @@ func (s *S3Storage) Store(key, path string) error {
1817
}
1918

2019
destination := fmt.Sprintf("%s/%s", s.Project, key)
21-
uploader := manager.NewUploader(s.Client)
22-
_, err = uploader.Upload(context.TODO(), &s3.PutObjectInput{
20+
_, err = s.Client.PutObject(context.TODO(), &s3.PutObjectInput{
2321
Bucket: &s.Bucket,
2422
Key: &destination,
2523
Body: file,

0 commit comments

Comments
 (0)