Skip to content

Commit 639deab

Browse files
jefchiensky333999
authored andcommitted
Migrate AWS API calls from SDK Go v1 to v2
Squashed application of the aws-sdk-v2 migration (feature/aws-sdk-v2) onto latest main. Replaces the SDKv1 credential chain, service clients, retryers, and request handlers with SDKv2 equivalents, and removes the hand-vendored SDKv1 cloudwatch/cloudwatchlogs services (~44k lines). Source PRs (Jeffrey Chien): - #1981 Support credential chain for AWS SDK Go v2 - #1985 Migrate CloudWatch exporter to SDKv2 - #1989 Migrate CloudWatch logs output plugin to SDKv2 - #1992 Migrate EC2 metadata to SDKv2 - #1994 Migrate ECS service discovery to SDKv2 - #1995 Migrate wizard, downloader, and translator to SDKv2 - #2001 Remove SDKv1 direct dependencies - Use a shared HTTP client to reduce file descriptor usage aws-sdk-go (v1) is no longer a direct dependency. cfg/aws now exposes the v2 credential chain (CredentialsConfig.LoadConfig), STS regional->partitional fallback, smithy custom-header middleware, and a shared BuildableClient.
1 parent c9c2266 commit 639deab

135 files changed

Lines changed: 4224 additions & 47096 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/PR-build.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,16 @@ jobs:
7272
if: needs.changes.outputs.lint == 'true'
7373
run: make lint
7474

75+
- name: Check AWS SDK partition data
76+
if: needs.changes.outputs.lint == 'true'
77+
run: |
78+
make copy-aws-sdk-partition
79+
if [ ! -z "`git status --porcelain`" ]; then
80+
echo "make copy-aws-sdk-partition changed files"
81+
git status
82+
exit 1
83+
fi
84+
7585
build:
7686
needs: [lint, changes]
7787
name: Build ${{ matrix.os }}

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ linters:
3333
- third_party$
3434
- builtin$
3535
- examples$
36+
- sdk/
3637
rules:
3738
- linters:
3839
- revive

Makefile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,18 @@ dockerized-windows-build:
391391
$(DOCKER_WINDOWS_BUILD_FROM_SOURCE) .
392392
@echo Built image:
393393
@echo $(IMAGE)
394+
395+
copy-aws-sdk-partition:
396+
# aws-sdk-go-v2 does not export partition metadata, so we need to copy the files from vendor to make it accessible
397+
# for the credential chain.
398+
go mod vendor
399+
cp vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partition.go ./sdk/endpoints/awsrulesfn/partition.go
400+
cp vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.go ./sdk/endpoints/awsrulesfn/partitions.go
401+
echo '// Code generated by aws-sdk-go-v2. DO NOT EDIT.' > temp_partition.go
402+
cat ./sdk/endpoints/awsrulesfn/partition.go >> temp_partition.go
403+
mv temp_partition.go ./sdk/endpoints/awsrulesfn/partition.go
404+
echo '// Code generated by aws-sdk-go-v2. DO NOT EDIT.' > temp_partitions.go
405+
cat ./sdk/endpoints/awsrulesfn/partitions.go >> temp_partitions.go
406+
mv temp_partitions.go ./sdk/endpoints/awsrulesfn/partitions.go
407+
rm -rf vendor/
408+
$(MAKE) fmt

cfg/aws/aws_sdk_logging.go

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,50 @@
44
package aws
55

66
import (
7+
"fmt"
78
"log"
89
"strings"
910

10-
"github.com/aws/aws-sdk-go/aws"
11+
"github.com/aws/aws-sdk-go-v2/aws"
12+
"github.com/aws/smithy-go/logging"
1113
)
1214

1315
// Hard coded strings that match actual variable names in the AWS SDK.
14-
// I don't expect these names to change, or their meaning to change.
15-
// Update this map if/when AWS SDK adds more levels (unlikely).
16-
var stringToLevelMap map[string]aws.LogLevelType = map[string]aws.LogLevelType{
17-
"LogDebug": aws.LogDebug,
18-
"LogDebugWithSigning": aws.LogDebugWithSigning,
19-
"LogDebugWithHTTPBody": aws.LogDebugWithHTTPBody,
20-
"LogDebugWithRequestRetries": aws.LogDebugWithRequestRetries,
21-
"LogDebugWithRequestErrors": aws.LogDebugWithRequestErrors,
22-
"LogDebugWithEventStreamBody": aws.LogDebugWithEventStreamBody,
16+
var stringToLevelMap = map[string]aws.ClientLogMode{
17+
// AWS SDK v2 Levels
18+
"LogRequest": aws.LogRequest,
19+
"LogResponse": aws.LogResponse,
20+
"LogSigning": aws.LogSigning,
21+
"LogRequestWithBody": aws.LogRequestWithBody,
22+
"LogResponseWithBody": aws.LogResponseWithBody,
23+
"LogRetries": aws.LogRetries,
24+
"LogRequestEventMessage": aws.LogRequestEventMessage,
25+
"LogResponseEventMessage": aws.LogResponseEventMessage,
26+
"LogDeprecatedUsage": aws.LogDeprecatedUsage,
27+
// AWS SDK v1 Levels
28+
"LogDebug": aws.LogRequest | aws.LogResponse,
29+
"LogDebugWithSigning": aws.LogRequest | aws.LogResponse | aws.LogSigning,
30+
"LogDebugWithHTTPBody": aws.LogRequestWithBody | aws.LogResponseWithBody,
31+
"LogDebugWithRequestRetries": aws.LogRequest | aws.LogResponse | aws.LogRetries,
32+
"LogDebugWithRequestErrors": aws.LogRequest | aws.LogResponse, // no equivalent in AWS SDK v2
33+
"LogDebugWithEventStreamBody": aws.LogRequestEventMessage | aws.LogResponseEventMessage,
2334
}
24-
var sdkLogLevel aws.LogLevelType = aws.LogOff
35+
var sdkLogLevel aws.ClientLogMode
2536

2637
// SetSDKLogLevel sets the global log level which will be used in all AWS SDK calls.
2738
// The levels are a bit field that is OR'd together.
2839
// So the user can specify multiple levels and we OR them together.
2940
// Example: "aws_sdk_log_level": "LogDebugWithSigning | LogDebugWithRequestErrors".
30-
// JSON string value must contain the levels seperated by "|" and optionally whitespace.
41+
// JSON string value must contain the levels separated by "|" and optionally whitespace.
3142
func SetSDKLogLevel(sdkLogLevelString string) {
32-
var temp aws.LogLevelType = aws.LogOff
43+
var temp aws.ClientLogMode
3344

3445
levels := strings.Split(sdkLogLevelString, "|")
3546
for _, v := range levels {
3647
trimmed := strings.TrimSpace(v)
48+
if trimmed == "LogDebugWithRequestErrors" {
49+
log.Println(`W! AWS SDK log level "LogDebugWithRequestErrors" is no longer supported. This will be evaluated as the equivalent of "LogDebug".`)
50+
}
3751
// If v not in map, then OR with 0 is harmless.
3852
temp |= stringToLevelMap[trimmed]
3953
}
@@ -43,17 +57,23 @@ func SetSDKLogLevel(sdkLogLevelString string) {
4357

4458
// SDKLogLevel returns the single global value so it can be used in all
4559
// AWS SDK calls scattered throughout the Agent.
46-
func SDKLogLevel() *aws.LogLevelType {
47-
return &sdkLogLevel
60+
func SDKLogLevel() aws.ClientLogMode {
61+
return sdkLogLevel
4862
}
4963

5064
// SDKLogger implements the aws.Logger interface.
5165
type SDKLogger struct {
5266
}
5367

54-
// Log is the only method in the aws.Logger interface.
55-
func (SDKLogger) Log(args ...interface{}) {
56-
// Always use info logging level.
57-
tempSlice := append([]interface{}{"I!"}, args...)
58-
log.Println(tempSlice...)
68+
var _ logging.Logger = (*SDKLogger)(nil)
69+
70+
func (SDKLogger) Logf(classification logging.Classification, format string, args ...interface{}) {
71+
logLevelPrefix := "I!"
72+
switch classification {
73+
case logging.Debug:
74+
logLevelPrefix = "D!"
75+
case logging.Warn:
76+
logLevelPrefix = "W!"
77+
}
78+
log.Printf(fmt.Sprintf("%s %s", logLevelPrefix, format), args...)
5979
}

cfg/aws/aws_sdk_logging_test.go

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,49 +4,83 @@
44
package aws
55

66
import (
7+
"bytes"
8+
"log"
9+
"os"
710
"testing"
811

9-
"github.com/aws/aws-sdk-go/aws"
12+
"github.com/aws/aws-sdk-go-v2/aws"
13+
"github.com/aws/smithy-go/logging"
14+
"github.com/stretchr/testify/assert"
1015
)
1116

1217
func TestSetSDKLogLevel(t *testing.T) {
13-
cases := []struct {
14-
sdkLogLevelString string
15-
expectedVal aws.LogLevelType
18+
testCases := []struct {
19+
input string
20+
want aws.ClientLogMode
1621
}{
17-
// sdkLogLevelString does not match
18-
{"FOO", aws.LogOff},
22+
// Invalid input
23+
{input: "FOO", want: aws.ClientLogMode(0)},
1924
// Wrong case.
20-
{"logDEBUG", aws.LogOff},
25+
{input: "logrequest", want: aws.ClientLogMode(0)},
2126
// Extra char.
22-
{"LogDebug1", aws.LogOff},
27+
{input: "LogRequest1", want: aws.ClientLogMode(0)},
2328
// Single match.
24-
{"LogDebug", aws.LogDebug},
25-
{"LogDebugWithEventStreamBody", aws.LogDebugWithEventStreamBody},
26-
{"LogDebugWithHTTPBody", aws.LogDebugWithHTTPBody},
27-
{"LogDebugWithRequestRetries", aws.LogDebugWithRequestRetries},
28-
{"LogDebugWithRequestErrors", aws.LogDebugWithRequestErrors},
29-
{"LogDebugWithEventStreamBody", aws.LogDebugWithEventStreamBody},
29+
{input: "LogRequest", want: aws.LogRequest},
30+
{input: "LogResponse", want: aws.LogResponse},
31+
{input: "LogSigning", want: aws.LogSigning},
32+
{input: "LogRequestWithBody", want: aws.LogRequestWithBody},
33+
{input: "LogResponseWithBody", want: aws.LogResponseWithBody},
34+
{input: "LogRetries", want: aws.LogRetries},
35+
{input: "LogRequestEventMessage", want: aws.LogRequestEventMessage},
36+
{input: "LogResponseEventMessage", want: aws.LogResponseEventMessage},
37+
{input: "LogDeprecatedUsage", want: aws.LogDeprecatedUsage},
38+
// v1 compatibility
39+
{input: "LogDebug", want: aws.LogRequest | aws.LogResponse},
40+
{input: "LogDebugWithSigning", want: aws.LogRequest | aws.LogResponse | aws.LogSigning},
41+
{input: "LogDebugWithHTTPBody", want: aws.LogRequestWithBody | aws.LogResponseWithBody},
42+
{input: "LogDebugWithRequestRetries", want: aws.LogRequest | aws.LogResponse | aws.LogRetries},
43+
{input: "LogDebugWithRequestErrors", want: aws.LogRequest | aws.LogResponse},
44+
{input: "LogDebugWithEventStreamBody", want: aws.LogRequestEventMessage | aws.LogResponseEventMessage},
3045
// Extra space around is allowed.
31-
{" LogDebug ", aws.LogDebug},
46+
{input: " LogRequest ", want: aws.LogRequest},
3247
// Multiple matches.
33-
{"LogDebugWithEventStreamBody|LogDebugWithHTTPBody",
34-
aws.LogDebugWithEventStreamBody | aws.LogDebugWithHTTPBody},
35-
{" LogDebugWithHTTPBody | LogDebugWithEventStreamBody ",
36-
aws.LogDebugWithEventStreamBody | aws.LogDebugWithHTTPBody},
37-
{"LogDebugWithRequestRetries|LogDebugWithEventStreamBody",
38-
aws.LogDebugWithEventStreamBody | aws.LogDebugWithRequestRetries},
39-
{"LogDebugWithRequestRetries|LogDebugWithRequestErrors",
40-
aws.LogDebugWithRequestRetries | aws.LogDebugWithRequestErrors},
41-
{"LogDebugWithRequestRetries|LogDebugWithRequestErrors|LogDebugWithEventStreamBody",
42-
aws.LogDebugWithRequestRetries | aws.LogDebugWithRequestErrors | aws.LogDebugWithEventStreamBody},
48+
{input: "LogRequest|LogResponse", want: aws.LogRequest | aws.LogResponse},
49+
{input: " LogRequestWithBody | LogResponseWithBody ", want: aws.LogRequestWithBody | aws.LogResponseWithBody},
50+
{input: "LogRetries|LogSigning", want: aws.LogRetries | aws.LogSigning},
51+
{input: "LogRequest|LogResponse|LogSigning", want: aws.LogRequest | aws.LogResponse | aws.LogSigning},
4352
}
4453

45-
for _, tc := range cases {
46-
SetSDKLogLevel(tc.sdkLogLevelString)
47-
// check the internal var
48-
if *SDKLogLevel() != tc.expectedVal {
49-
t.Errorf("input: %v, actual: %v", tc, sdkLogLevel)
50-
}
54+
for _, testCase := range testCases {
55+
SetSDKLogLevel(testCase.input)
56+
assert.Equal(t, testCase.want, SDKLogLevel())
57+
}
58+
}
59+
60+
func TestSDKLogger(t *testing.T) {
61+
var buf bytes.Buffer
62+
log.SetOutput(&buf)
63+
defer log.SetOutput(os.Stderr)
64+
65+
logger := SDKLogger{}
66+
67+
tests := []struct {
68+
classification logging.Classification
69+
expectedPrefix string
70+
}{
71+
{classification: logging.Debug, expectedPrefix: "D!"},
72+
{classification: logging.Warn, expectedPrefix: "W!"},
73+
{classification: logging.Classification("TEST"), expectedPrefix: "I!"},
74+
}
75+
76+
for _, tt := range tests {
77+
t.Run(string(tt.classification), func(t *testing.T) {
78+
buf.Reset()
79+
logger.Logf(tt.classification, "test message: %s", "arg")
80+
81+
output := buf.String()
82+
assert.Contains(t, output, tt.expectedPrefix)
83+
assert.Contains(t, output, "test message: arg")
84+
})
5185
}
5286
}

cfg/aws/client.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package aws
5+
6+
import (
7+
"sync"
8+
"time"
9+
10+
"github.com/aws/aws-sdk-go-v2/aws"
11+
awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"
12+
)
13+
14+
var (
15+
sharedHTTPClient aws.HTTPClient
16+
sharedHTTPClientOnce sync.Once
17+
)
18+
19+
// getSharedHTTPClient returns a singleton HTTP client for all AWS SDK operations. Sharing the client enables connection
20+
// pooling and reuse across all AWS API calls, which reduces memory and file descriptor usage. It has to be an
21+
// BuildableClient because the SDK will only append custom CA bundles if the client is of that type.
22+
// https://github.com/aws/aws-sdk-go-v2/blob/v1.41.1/config/resolve.go#L57
23+
func getSharedHTTPClient() aws.HTTPClient {
24+
sharedHTTPClientOnce.Do(func() {
25+
sharedHTTPClient = awshttp.NewBuildableClient().WithTimeout(1 * time.Minute)
26+
})
27+
return sharedHTTPClient
28+
}

cfg/aws/client_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package aws
5+
6+
import (
7+
"sync"
8+
"testing"
9+
10+
"github.com/aws/aws-sdk-go-v2/aws"
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
func TestGetSharedHTTPClient_Concurrent(t *testing.T) {
15+
sharedHTTPClientOnce = sync.Once{}
16+
sharedHTTPClient = nil
17+
18+
const count = 100
19+
clients := make([]aws.HTTPClient, count)
20+
var wg sync.WaitGroup
21+
22+
for i := 0; i < count; i++ {
23+
wg.Add(1)
24+
go func(index int) {
25+
defer wg.Done()
26+
clients[index] = getSharedHTTPClient()
27+
}(i)
28+
}
29+
30+
wg.Wait()
31+
32+
// All goroutines should get the same instance
33+
first := clients[0]
34+
assert.NotNil(t, first)
35+
for i := 1; i < count; i++ {
36+
assert.Same(t, first, clients[i])
37+
}
38+
}

0 commit comments

Comments
 (0)