Skip to content

Commit c7ce574

Browse files
authored
Migrate to AWS SDK v2 for S3 client in CirrusCIMock (#996)
1 parent 0d42e25 commit c7ce574

File tree

4 files changed

+88
-61
lines changed

4 files changed

+88
-61
lines changed

go.mod

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ require (
6262
require (
6363
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4
6464
github.com/IGLOU-EU/go-wildcard v1.0.3
65-
github.com/aws/aws-sdk-go v1.55.8
65+
github.com/aws/aws-sdk-go-v2 v1.39.6
66+
github.com/aws/aws-sdk-go-v2/config v1.31.17
67+
github.com/aws/aws-sdk-go-v2/credentials v1.18.21
68+
github.com/aws/aws-sdk-go-v2/service/s3 v1.90.0
69+
github.com/aws/smithy-go v1.23.2
6670
github.com/bartventer/httpcache v0.12.0
6771
github.com/bmatcuk/doublestar v1.3.4
6872
github.com/cirruslabs/chacha v0.16.3
@@ -119,17 +123,19 @@ require (
119123
github.com/ProtonMail/go-crypto v1.3.0 // indirect
120124
github.com/agext/levenshtein v1.2.3 // indirect
121125
github.com/ajg/form v1.5.1 // indirect
122-
github.com/aws/aws-sdk-go-v2 v1.39.6 // indirect
123126
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 // indirect
127+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 // indirect
124128
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 // indirect
125129
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 // indirect
130+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
126131
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 // indirect
127132
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect
128133
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 // indirect
129134
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect
130135
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 // indirect
131-
github.com/aws/aws-sdk-go-v2/service/s3 v1.90.0 // indirect
132-
github.com/aws/smithy-go v1.23.2 // indirect
136+
github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 // indirect
137+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 // indirect
138+
github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 // indirect
133139
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
134140
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
135141
github.com/cespare/xxhash/v2 v2.3.0 // indirect
@@ -171,7 +177,6 @@ require (
171177
github.com/in-toto/in-toto-golang v0.9.0 // indirect
172178
github.com/inconshreveable/mousetrap v1.1.0 // indirect
173179
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
174-
github.com/jmespath/go-jmespath v0.4.0 // indirect
175180
github.com/joshdk/go-junit v1.0.0 // indirect
176181
github.com/kevinburke/ssh_config v1.2.0 // indirect
177182
github.com/klauspost/compress v1.18.1 // indirect

go.sum

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
4444
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
4545
github.com/avast/retry-go/v4 v4.7.0 h1:yjDs35SlGvKwRNSykujfjdMxMhMQQM0TnIjJaHB+Zio=
4646
github.com/avast/retry-go/v4 v4.7.0/go.mod h1:ZMPDa3sY2bKgpLtap9JRUgk2yTAba7cgiFhqxY2Sg6Q=
47-
github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ=
48-
github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk=
4947
github.com/aws/aws-sdk-go-v2 v1.39.6 h1:2JrPCVgWJm7bm83BDwY5z8ietmeJUbh3O2ACnn+Xsqk=
5048
github.com/aws/aws-sdk-go-v2 v1.39.6/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
5149
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0=
@@ -308,10 +306,6 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
308306
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
309307
github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=
310308
github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=
311-
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
312-
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
313-
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
314-
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
315309
github.com/joshdk/go-junit v0.0.0-20200312181801-e5d93c0f31a8/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung=
316310
github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE=
317311
github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung=

internal/agent/http_cache/ghacache/cirruscimock/cirruscimock.go

Lines changed: 63 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import (
44
"bytes"
55
"context"
66
"errors"
7-
"github.com/aws/aws-sdk-go/aws"
8-
"github.com/aws/aws-sdk-go/aws/awserr"
9-
"github.com/aws/aws-sdk-go/service/s3"
7+
"github.com/aws/aws-sdk-go-v2/aws"
8+
"github.com/aws/aws-sdk-go-v2/service/s3"
9+
"github.com/aws/aws-sdk-go-v2/service/s3/types"
10+
"github.com/aws/smithy-go"
11+
smithyhttp "github.com/aws/smithy-go/transport/http"
1012
"github.com/cirruslabs/cirrus-cli/pkg/api"
1113
"github.com/samber/lo"
1214
"github.com/stretchr/testify/require"
@@ -24,20 +26,20 @@ import (
2426
)
2527

2628
type cirrusCIMock struct {
27-
s3Client *s3.S3
29+
s3Client *s3.Client
2830
s3Bucket *string
2931

3032
api.UnimplementedCirrusCIServiceServer
3133
bytestream.UnimplementedByteStreamServer
3234
}
3335

34-
func newCirrusCIMock(t *testing.T, s3Client *s3.S3) *cirrusCIMock {
36+
func newCirrusCIMock(t *testing.T, s3Client *s3.Client) *cirrusCIMock {
3537
mock := &cirrusCIMock{
3638
s3Client: s3Client,
3739
s3Bucket: aws.String("test"),
3840
}
3941

40-
_, err := mock.s3Client.CreateBucket(&s3.CreateBucketInput{
42+
_, err := mock.s3Client.CreateBucket(context.Background(), &s3.CreateBucketInput{
4143
Bucket: mock.s3Bucket,
4244
})
4345
require.NoError(t, err)
@@ -113,7 +115,7 @@ func (mock *cirrusCIMock) Write(stream bytestream.ByteStream_WriteServer) error
113115
return status.Error(codes.FailedPrecondition, "attempted to upload cache without specifying resource name")
114116
}
115117

116-
_, err := mock.s3Client.PutObjectWithContext(stream.Context(), &s3.PutObjectInput{
118+
_, err := mock.s3Client.PutObject(stream.Context(), &s3.PutObjectInput{
117119
Bucket: mock.s3Bucket,
118120
Key: aws.String(resourceName),
119121
Body: bytes.NewReader(buf.Bytes()),
@@ -128,13 +130,12 @@ func (mock *cirrusCIMock) Write(stream bytestream.ByteStream_WriteServer) error
128130
}
129131

130132
func (mock *cirrusCIMock) Read(request *bytestream.ReadRequest, stream bytestream.ByteStream_ReadServer) error {
131-
result, err := mock.s3Client.GetObjectWithContext(stream.Context(), &s3.GetObjectInput{
133+
result, err := mock.s3Client.GetObject(stream.Context(), &s3.GetObjectInput{
132134
Bucket: mock.s3Bucket,
133135
Key: aws.String(request.ResourceName),
134136
})
135137
if err != nil {
136-
var aerr awserr.Error
137-
if errors.As(err, &aerr) && aerr.Code() == s3.ErrCodeNoSuchKey {
138+
if isS3NotFound(err) {
138139
return status.Errorf(codes.NotFound, "cache entry for key %s is not found",
139140
request.ResourceName)
140141
}
@@ -165,54 +166,51 @@ func (mock *cirrusCIMock) Read(request *bytestream.ReadRequest, stream bytestrea
165166
}
166167

167168
func (mock *cirrusCIMock) GenerateCacheUploadURL(ctx context.Context, request *api.CacheKey) (*api.GenerateURLResponse, error) {
168-
putObjectRequest, _ := mock.s3Client.PutObjectRequest(&s3.PutObjectInput{
169+
presignClient := s3.NewPresignClient(mock.s3Client)
170+
presignResult, err := presignClient.PresignPutObject(ctx, &s3.PutObjectInput{
169171
Bucket: mock.s3Bucket,
170172
Key: aws.String(request.CacheKey),
171-
})
172-
173-
url, _, err := putObjectRequest.PresignRequest(10 * time.Minute)
173+
}, s3.WithPresignExpires(10*time.Minute))
174174
if err != nil {
175175
return nil, err
176176
}
177177

178178
return &api.GenerateURLResponse{
179-
Url: url,
179+
Url: presignResult.URL,
180180
}, nil
181181
}
182182

183183
func (mock *cirrusCIMock) GenerateCacheDownloadURLs(
184-
_ context.Context,
184+
ctx context.Context,
185185
request *api.CacheKey,
186186
) (*api.GenerateURLsResponse, error) {
187-
getObjectRequest, _ := mock.s3Client.GetObjectRequest(&s3.GetObjectInput{
187+
presignClient := s3.NewPresignClient(mock.s3Client)
188+
presignResult, err := presignClient.PresignGetObject(ctx, &s3.GetObjectInput{
188189
Bucket: mock.s3Bucket,
189190
Key: aws.String(request.CacheKey),
190-
})
191-
192-
url, _, err := getObjectRequest.PresignRequest(10 * time.Minute)
191+
}, s3.WithPresignExpires(10*time.Minute))
193192
if err != nil {
194193
return nil, err
195194
}
196195

197196
return &api.GenerateURLsResponse{
198-
Urls: []string{url},
197+
Urls: []string{presignResult.URL},
199198
}, nil
200199
}
201200

202201
func (mock *cirrusCIMock) CacheInfo(ctx context.Context, request *api.CacheInfoRequest) (*api.CacheInfoResponse, error) {
203-
result, err := mock.s3Client.HeadObjectWithContext(ctx, &s3.HeadObjectInput{
202+
result, err := mock.s3Client.HeadObject(ctx, &s3.HeadObjectInput{
204203
Bucket: mock.s3Bucket,
205204
Key: aws.String(request.CacheKey),
206205
})
207206
if err != nil {
208-
var requestFailure awserr.RequestFailure
209-
if errors.As(err, &requestFailure) && requestFailure.StatusCode() == http.StatusNotFound {
207+
if isS3NotFound(err) {
210208
// Try to match cache entry by key prefixes as a fallback
211209
for _, cacheKeyPrefix := range request.CacheKeyPrefixes {
212-
result, err := mock.s3Client.ListObjectsWithContext(ctx, &s3.ListObjectsInput{
210+
result, err := mock.s3Client.ListObjects(ctx, &s3.ListObjectsInput{
213211
Bucket: mock.s3Bucket,
214212
Prefix: aws.String(cacheKeyPrefix),
215-
MaxKeys: aws.Int64(1),
213+
MaxKeys: aws.Int32(1),
216214
})
217215
if err != nil {
218216
return nil, err
@@ -246,7 +244,7 @@ func (mock *cirrusCIMock) CacheInfo(ctx context.Context, request *api.CacheInfoR
246244
}
247245

248246
func (mock *cirrusCIMock) MultipartCacheUploadCreate(ctx context.Context, request *api.CacheKey) (*api.MultipartCacheUploadCreateResponse, error) {
249-
result, err := mock.s3Client.CreateMultipartUploadWithContext(ctx, &s3.CreateMultipartUploadInput{
247+
result, err := mock.s3Client.CreateMultipartUpload(ctx, &s3.CreateMultipartUploadInput{
250248
Bucket: mock.s3Bucket,
251249
Key: aws.String(request.CacheKey),
252250
})
@@ -260,41 +258,40 @@ func (mock *cirrusCIMock) MultipartCacheUploadCreate(ctx context.Context, reques
260258
}
261259

262260
func (mock *cirrusCIMock) MultipartCacheUploadPart(ctx context.Context, request *api.MultipartCacheUploadPartRequest) (*api.GenerateURLResponse, error) {
263-
uploadPartRequest, _ := mock.s3Client.UploadPartRequest(&s3.UploadPartInput{
261+
presignClient := s3.NewPresignClient(mock.s3Client)
262+
presignResult, err := presignClient.PresignUploadPart(ctx, &s3.UploadPartInput{
264263
Bucket: mock.s3Bucket,
265264
Key: aws.String(request.CacheKey.CacheKey),
266265
UploadId: aws.String(request.UploadId),
267-
PartNumber: aws.Int64(int64(request.PartNumber)),
268-
})
269-
270-
url, headers, err := uploadPartRequest.PresignRequest(10 * time.Minute)
266+
PartNumber: aws.Int32(int32(request.PartNumber)),
267+
}, s3.WithPresignExpires(10*time.Minute))
271268
if err != nil {
272269
return nil, err
273270
}
274271

275272
return &api.GenerateURLResponse{
276-
Url: url,
277-
ExtraHeaders: lo.MapEntries(headers, func(key string, value []string) (string, string) {
273+
Url: presignResult.URL,
274+
ExtraHeaders: lo.MapEntries(presignResult.SignedHeader, func(key string, value []string) (string, string) {
278275
return key, value[0]
279276
}),
280277
}, nil
281278
}
282279

283280
func (mock *cirrusCIMock) MultipartCacheUploadCommit(ctx context.Context, request *api.MultipartCacheUploadCommitRequest) (*emptypb.Empty, error) {
284-
var parts []*s3.CompletedPart
281+
var parts []types.CompletedPart
285282

286283
for _, part := range request.Parts {
287-
parts = append(parts, &s3.CompletedPart{
288-
PartNumber: aws.Int64(int64(part.PartNumber)),
284+
parts = append(parts, types.CompletedPart{
285+
PartNumber: aws.Int32(int32(part.PartNumber)),
289286
ETag: aws.String(part.Etag),
290287
})
291288
}
292289

293-
_, err := mock.s3Client.CompleteMultipartUploadWithContext(ctx, &s3.CompleteMultipartUploadInput{
290+
_, err := mock.s3Client.CompleteMultipartUpload(ctx, &s3.CompleteMultipartUploadInput{
294291
Bucket: mock.s3Bucket,
295292
Key: aws.String(request.CacheKey.CacheKey),
296293
UploadId: aws.String(request.UploadId),
297-
MultipartUpload: &s3.CompletedMultipartUpload{
294+
MultipartUpload: &types.CompletedMultipartUpload{
298295
Parts: parts,
299296
},
300297
})
@@ -304,3 +301,30 @@ func (mock *cirrusCIMock) MultipartCacheUploadCommit(ctx context.Context, reques
304301

305302
return &emptypb.Empty{}, nil
306303
}
304+
305+
func isS3NotFound(err error) bool {
306+
var noSuchKey *types.NoSuchKey
307+
if errors.As(err, &noSuchKey) {
308+
return true
309+
}
310+
311+
var notFound *types.NotFound
312+
if errors.As(err, &notFound) {
313+
return true
314+
}
315+
316+
var apiErr smithy.APIError
317+
if errors.As(err, &apiErr) {
318+
switch apiErr.ErrorCode() {
319+
case "NoSuchKey", "NotFound":
320+
return true
321+
}
322+
}
323+
324+
var responseErr *smithyhttp.ResponseError
325+
if errors.As(err, &responseErr) && responseErr.HTTPStatusCode() == http.StatusNotFound {
326+
return true
327+
}
328+
329+
return false
330+
}

internal/agent/http_cache/ghacache/cirruscimock/s3client.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@ package cirruscimock
33
import (
44
"context"
55
"fmt"
6-
"github.com/aws/aws-sdk-go/aws"
7-
"github.com/aws/aws-sdk-go/aws/credentials"
8-
"github.com/aws/aws-sdk-go/aws/session"
9-
"github.com/aws/aws-sdk-go/service/s3"
6+
"github.com/aws/aws-sdk-go-v2/aws"
7+
"github.com/aws/aws-sdk-go-v2/config"
8+
"github.com/aws/aws-sdk-go-v2/credentials"
9+
"github.com/aws/aws-sdk-go-v2/service/s3"
1010
"github.com/docker/go-connections/nat"
1111
"github.com/stretchr/testify/require"
1212
"github.com/testcontainers/testcontainers-go"
1313
"github.com/testcontainers/testcontainers-go/wait"
1414
"testing"
1515
)
1616

17-
func S3Client(t *testing.T) *s3.S3 {
17+
func S3Client(t *testing.T) *s3.Client {
1818
t.Helper()
1919

2020
ctx := context.Background()
@@ -35,12 +35,16 @@ func S3Client(t *testing.T) *s3.S3 {
3535
mappedPort, err := localstackContainer.MappedPort(ctx, exposedPort)
3636
require.NoError(t, err)
3737

38-
session, err := session.NewSession(&aws.Config{
39-
Endpoint: aws.String(fmt.Sprintf("http://test.s3.localhost.localstack.cloud:%d/", mappedPort.Int())),
40-
Region: aws.String("us-east-1"),
41-
Credentials: credentials.NewStaticCredentials("id", "secret", ""),
42-
})
38+
endpoint := fmt.Sprintf("http://s3.localhost.localstack.cloud:%d", mappedPort.Int())
39+
40+
cfg, err := config.LoadDefaultConfig(ctx,
41+
config.WithRegion("us-east-1"),
42+
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("id", "secret", "")),
43+
)
4344
require.NoError(t, err)
4445

45-
return s3.New(session)
46+
return s3.NewFromConfig(cfg, func(options *s3.Options) {
47+
options.BaseEndpoint = aws.String(endpoint)
48+
options.UsePathStyle = true
49+
})
4650
}

0 commit comments

Comments
 (0)