diff --git a/.github/workflows/deps.yml b/.github/workflows/deps.yml index ee5a5f71c2..91e0303c12 100644 --- a/.github/workflows/deps.yml +++ b/.github/workflows/deps.yml @@ -4,6 +4,7 @@ on: branches: - "master" - "release*" + - "sdkv2" permissions: contents: read jobs: diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index ef244eae7d..470ef64e53 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -5,6 +5,7 @@ on: branches: - "master" - "release*" + - "sdk*" permissions: id-token: write diff --git a/.github/workflows/pr-automated-tests.yaml b/.github/workflows/pr-automated-tests.yaml index e4b45bd48f..3796ac5ac8 100644 --- a/.github/workflows/pr-automated-tests.yaml +++ b/.github/workflows/pr-automated-tests.yaml @@ -4,6 +4,7 @@ on: branches: - "master" - "release*" + - "sdkv2*" permissions: contents: read jobs: diff --git a/cmd/cni-metrics-helper/metrics/metrics.go b/cmd/cni-metrics-helper/metrics/metrics.go index fc3f2ff42f..eae4e9e982 100644 --- a/cmd/cni-metrics-helper/metrics/metrics.go +++ b/cmd/cni-metrics-helper/metrics/metrics.go @@ -19,8 +19,8 @@ import ( "context" "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" + "github.com/aws/aws-sdk-go-v2/aws" + cloudwatchtypes "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" "k8s.io/client-go/kubernetes" @@ -288,9 +288,9 @@ func produceHistogram(act metricsAction, cw publisher.Publisher) { prevUpperBound = *bucket.UpperBound if *bucket.CumulativeCount != 0 { - dataPoint := &cloudwatch.MetricDatum{ + dataPoint := cloudwatchtypes.MetricDatum{ MetricName: aws.String(act.cwMetricName), - StatisticValues: &cloudwatch.StatisticSet{ + StatisticValues: &cloudwatchtypes.StatisticSet{ Maximum: aws.Float64(mid), Minimum: aws.Float64(mid), SampleCount: aws.Float64(*bucket.CumulativeCount), @@ -322,23 +322,23 @@ func produceCloudWatchMetrics(t metricsTarget, families map[string]*dto.MetricFa for _, action := range convertMetrics.actions { switch metricType { case dto.MetricType_COUNTER: - dataPoint := &cloudwatch.MetricDatum{ + dataPoint := cloudwatchtypes.MetricDatum{ MetricName: aws.String(action.cwMetricName), - Unit: aws.String(cloudwatch.StandardUnitCount), + Unit: cloudwatchtypes.StandardUnitCount, Value: aws.Float64(action.data.curSingleDataPoint), } cw.Publish(dataPoint) case dto.MetricType_GAUGE: - dataPoint := &cloudwatch.MetricDatum{ + dataPoint := cloudwatchtypes.MetricDatum{ MetricName: aws.String(action.cwMetricName), - Unit: aws.String(cloudwatch.StandardUnitCount), + Unit: cloudwatchtypes.StandardUnitCount, Value: aws.Float64(action.data.curSingleDataPoint), } cw.Publish(dataPoint) case dto.MetricType_SUMMARY: - dataPoint := &cloudwatch.MetricDatum{ + dataPoint := cloudwatchtypes.MetricDatum{ MetricName: aws.String(action.cwMetricName), - Unit: aws.String(cloudwatch.StandardUnitCount), + Unit: cloudwatchtypes.StandardUnitCount, Value: aws.Float64(action.data.curSingleDataPoint), } cw.Publish(dataPoint) diff --git a/cmd/routed-eni-cni-plugin/cni_test.go b/cmd/routed-eni-cni-plugin/cni_test.go index eaa3c70a12..4535b08ac0 100644 --- a/cmd/routed-eni-cni-plugin/cni_test.go +++ b/cmd/routed-eni-cni-plugin/cni_test.go @@ -21,7 +21,7 @@ import ( "github.com/aws/amazon-vpc-cni-k8s/pkg/sgpp" "github.com/aws/amazon-vpc-cni-k8s/pkg/utils/logger" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" current "github.com/containernetworking/cni/pkg/types/100" "github.com/containernetworking/cni/pkg/skel" diff --git a/go.mod b/go.mod index c715537b3c..ca6a8cbfa9 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,16 @@ require ( github.com/apparentlymart/go-cidr v1.1.0 github.com/aws/amazon-vpc-cni-k8s/test/agent v0.0.0-20231212223725-21c4bd73015b github.com/aws/amazon-vpc-resource-controller-k8s v1.5.0 - github.com/aws/aws-sdk-go v1.55.5 + github.com/aws/aws-sdk-go-v2 v1.32.5 + github.com/aws/aws-sdk-go-v2/config v1.28.4 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 + github.com/aws/aws-sdk-go-v2/service/autoscaling v1.50.0 + github.com/aws/aws-sdk-go-v2/service/cloudformation v1.56.0 + github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.43.0 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.189.0 + github.com/aws/aws-sdk-go-v2/service/eks v1.52.1 + github.com/aws/aws-sdk-go-v2/service/iam v1.38.1 + github.com/aws/smithy-go v1.22.1 github.com/containernetworking/cni v1.2.3 github.com/containernetworking/plugins v1.5.1 github.com/coreos/go-iptables v0.8.0 @@ -50,6 +59,16 @@ require ( github.com/Masterminds/squirrel v1.5.4 // indirect github.com/Microsoft/hcsshim v0.12.3 // indirect github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect + github.com/aws/aws-sdk-go v1.51.32 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.45 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect diff --git a/go.sum b/go.sum index ebaeb78073..2699371c68 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,46 @@ github.com/aws/amazon-vpc-cni-k8s/test/agent v0.0.0-20231212223725-21c4bd73015b github.com/aws/amazon-vpc-cni-k8s/test/agent v0.0.0-20231212223725-21c4bd73015b/go.mod h1:NvS1b2fBgkUvAWgBF8h0aRaVVoUeIlpUMnlTW2wIqik= github.com/aws/amazon-vpc-resource-controller-k8s v1.5.0 h1:utc5JzVlbORZ/4IFHb4yleqbIOKEevKfVxozKvhJWok= github.com/aws/amazon-vpc-resource-controller-k8s v1.5.0/go.mod h1:3q5gDG44vGr9ERe0YMHItThKXxDkntAUrlfTgJkdgF8= -github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= -github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go v1.51.32 h1:A6mPui7QP4mwmovyzgtdedbRbNur1Iu0/El7hBWNHms= +github.com/aws/aws-sdk-go v1.51.32/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.32.5 h1:U8vdWJuY7ruAkzaOdD7guwJjD06YSKmnKCJs7s3IkIo= +github.com/aws/aws-sdk-go-v2 v1.32.5/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= +github.com/aws/aws-sdk-go-v2/config v1.28.4 h1:qgD0MKmkIzZR2DrAjWJcI9UkndjR+8f6sjUQvXh0mb0= +github.com/aws/aws-sdk-go-v2/config v1.28.4/go.mod h1:LgnWnNzHZw4MLplSyEGia0WgJ/kCGD86zGCjvNpehJs= +github.com/aws/aws-sdk-go-v2/credentials v1.17.45 h1:DUgm5lFso57E7150RBgu1JpVQoF8fAPretiDStIuVjg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.45/go.mod h1:dnBpENcPC1ekZrGpSWspX+ZRGzhkvqngT2Qp5xBR1dY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 h1:woXadbf0c7enQ2UGCi8gW/WuKmE0xIzxBF/eD94jMKQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19/go.mod h1:zminj5ucw7w0r65bP6nhyOd3xL6veAUMc3ElGMoLVb4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 h1:4usbeaes3yJnCFC7kfeyhkdkPtoRYPa/hTmCqMpKpLI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24/go.mod h1:5CI1JemjVwde8m2WG3cz23qHKPOxbpkq0HaoreEgLIY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 h1:N1zsICrQglfzaBnrfM0Ys00860C+QFwu6u/5+LomP+o= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24/go.mod h1:dCn9HbJ8+K31i8IQ8EWmWj0EiIk0+vKiHNMxTTYveAg= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.50.0 h1:5tF6T8pAKna0TZ2g77jKdTCKoIRDsaYlYxz9OC1BraI= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.50.0/go.mod h1:I1+/2m+IhnK5qEbhS3CrzjeiVloo9sItE/2K+so0fkU= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.56.0 h1:zmXJiEm/fQYtFDLIUsZrcPIjTrL3R/noFICGlYBj3Ww= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.56.0/go.mod h1:9nOjXCDKE+QMK4JaCrLl36PU+VEfJmI7WVehYmojO8s= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.43.0 h1:r1sp92LSk4Gx8l0gScEjzSN+4iiImDvNayY9JYPNtNI= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.43.0/go.mod h1:fkETEwhdw2tOqu5m0Xa3wimV3PLDaiGqNrVZ3MJ7zOc= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.189.0 h1:eBriSsQa4r7aiKF2wv1EGYbK3X1VnjAYvdOlepBUi8s= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.189.0/go.mod h1:0A17IIeys01WfjDKehspGP+Cyo/YH/eNADIbEbRS9yM= +github.com/aws/aws-sdk-go-v2/service/eks v1.52.1 h1:XqyUdJbXQxY48CbBtN9a51HoTQy/kTIwrWiruRDsydk= +github.com/aws/aws-sdk-go-v2/service/eks v1.52.1/go.mod h1:WTfZ/+I7aSMEna6iYm1Kjne9A8f1MyxXNfp6hCa1+Bk= +github.com/aws/aws-sdk-go-v2/service/iam v1.38.1 h1:hfkzDZHBp9jAT4zcd5mtqckpU4E3Ax0LQaEWWk1VgN8= +github.com/aws/aws-sdk-go-v2/service/iam v1.38.1/go.mod h1:u36ahDtZcQHGmVm/r+0L1sfKX4fzLEMdCqiKRKkUMVM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 h1:tHxQi/XHPK0ctd/wdOw0t7Xrc2OxcRCnVzv8lwWPu0c= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4/go.mod h1:4GQbF1vJzG60poZqWatZlhP31y8PGCCVTvIGPdaaYJ0= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 h1:HJwZwRt2Z2Tdec+m+fPjvdmkq2s9Ra+VR0hjF7V2o40= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.5/go.mod h1:wrMCEwjFPms+V86TCQQeOxQF/If4vT44FGIOFiMC2ck= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 h1:zcx9LiGWZ6i6pjdcoE9oXAB6mUdeyC36Ia/QEiIvYdg= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4/go.mod h1:Tp/ly1cTjRLGBBmNccFumbZ8oqpZlpdhFf80SrRh4is= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.0 h1:s7LRgBqhwLaxcocnAniBJp7gaAB+4I4vHzqUqjH18yc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.0/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= +github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= +github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= diff --git a/pkg/awsutils/awssession/session.go b/pkg/awsutils/awssession/session.go index e26f75a39c..5927e32b06 100644 --- a/pkg/awsutils/awssession/session.go +++ b/pkg/awsutils/awssession/session.go @@ -14,20 +14,24 @@ package awssession import ( + "context" "fmt" "net/http" "os" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/smithy-go" + smithymiddleware "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "strconv" "time" "github.com/aws/amazon-vpc-cni-k8s/pkg/utils/logger" "github.com/aws/amazon-vpc-cni-k8s/utils" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ec2" ) // Http client timeout env for sessions @@ -58,43 +62,84 @@ func getHTTPTimeout() time.Duration { return httpTimeoutValue } -// New will return an session for service clients -func New() *session.Session { - awsCfg := aws.Config{ - MaxRetries: aws.Int(maxRetries), - HTTPClient: &http.Client{ - Timeout: getHTTPTimeout(), - }, - STSRegionalEndpoint: endpoints.RegionalSTSEndpoint, +// New will return aws.Config to be used by Service Clients. +func New(ctx context.Context) (aws.Config, error) { + customHTTPClient := &http.Client{ + Timeout: getHTTPTimeout()} + optFns := []func(*config.LoadOptions) error{ + config.WithHTTPClient(customHTTPClient), + config.WithRetryMaxAttempts(maxRetries), + config.WithRetryer(func() aws.Retryer { + return retry.NewStandard() + }), + injectUserAgent, } endpoint := os.Getenv("AWS_EC2_ENDPOINT") if endpoint != "" { - customResolver := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) { - if service == ec2.EndpointsID { - return endpoints.ResolvedEndpoint{ - URL: endpoint, - }, nil - } - return endpoints.DefaultResolver().EndpointFor(service, region, optFns...) - } - awsCfg.EndpointResolver = endpoints.ResolverFunc(customResolver) + optFns = append(optFns, config.WithEndpointResolver(aws.EndpointResolverFunc( + func(service, region string) (aws.Endpoint, error) { + if service == ec2.ServiceID { + return aws.Endpoint{ + URL: endpoint, + }, nil + } + // Fall back to default resolution + return aws.Endpoint{}, &aws.EndpointNotFoundError{} + }))) + } - sess := session.Must(session.NewSession(&awsCfg)) - //injecting session handler info - injectUserAgent(&sess.Handlers) + cfg, err := config.LoadDefaultConfig(ctx, optFns...) + + if err != nil { + return aws.Config{}, fmt.Errorf("failed to load AWS config: %w", err) + } - return sess + return cfg, nil } // injectUserAgent will inject app specific user-agent into awsSDK -func injectUserAgent(handlers *request.Handlers) { +func injectUserAgent(loadOptions *config.LoadOptions) error { version := utils.GetEnv(envVpcCniVersion, "") - handlers.Build.PushFrontNamed(request.NamedHandler{ - Name: fmt.Sprintf("%s/user-agent", "amazon-vpc-cni-k8s"), - Fn: request.MakeAddToUserAgentHandler( - "amazon-vpc-cni-k8s", - "version/"+version), + userAgent := fmt.Sprintf("amazon-vpc-cni-k8s/version/%s", version) + + loadOptions.APIOptions = append(loadOptions.APIOptions, func(stack *smithymiddleware.Stack) error { + return stack.Build.Add(&addUserAgentMiddleware{ + userAgent: userAgent, + }, smithymiddleware.After) }) + + return nil +} + +type addUserAgentMiddleware struct { + userAgent string +} + +func (m *addUserAgentMiddleware) HandleBuild(ctx context.Context, in smithymiddleware.BuildInput, next smithymiddleware.BuildHandler) (out smithymiddleware.BuildOutput, metadata smithymiddleware.Metadata, err error) { + // Simply pass through to the next handler in the middleware chain + return next.HandleBuild(ctx, in) +} + +func (m *addUserAgentMiddleware) ID() string { + return "AddUserAgent" +} + +func (m *addUserAgentMiddleware) HandleFinalize(ctx context.Context, in smithymiddleware.FinalizeInput, next smithymiddleware.FinalizeHandler) ( + out smithymiddleware.FinalizeOutput, metadata smithymiddleware.Metadata, err error) { + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown request type %T", in.Request)} + } + + userAgent := req.Header.Get("User-Agent") + if userAgent == "" { + userAgent = m.userAgent + } else { + userAgent += " " + m.userAgent + } + req.Header.Set("User-Agent", userAgent) + + return next.HandleFinalize(ctx, in) } diff --git a/pkg/awsutils/awssession/session_test.go b/pkg/awsutils/awssession/session_test.go index 1ca9e4e7bf..6798929a73 100644 --- a/pkg/awsutils/awssession/session_test.go +++ b/pkg/awsutils/awssession/session_test.go @@ -1,11 +1,12 @@ package awssession import ( + "context" "os" "testing" "time" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/stretchr/testify/assert" ) @@ -25,13 +26,15 @@ func TestHttpTimeoutWithValueAbove10(t *testing.T) { func TestAwsEc2EndpointResolver(t *testing.T) { customEndpoint := "https://ec2.us-west-2.customaws.com" + ctx := context.Background() os.Setenv("AWS_EC2_ENDPOINT", customEndpoint) defer os.Unsetenv("AWS_EC2_ENDPOINT") - sess := New() + cfg, err := New(ctx) + assert.NoError(t, err) - resolvedEndpoint, err := sess.Config.EndpointResolver.EndpointFor(ec2.EndpointsID, "") + resolvedEndpoint, err := cfg.EndpointResolver.ResolveEndpoint(ec2.ServiceID, "") assert.NoError(t, err) assert.Equal(t, customEndpoint, resolvedEndpoint.URL) } diff --git a/pkg/awsutils/awsutils.go b/pkg/awsutils/awsutils.go index c037622ad8..43256cdc86 100644 --- a/pkg/awsutils/awsutils.go +++ b/pkg/awsutils/awsutils.go @@ -18,6 +18,7 @@ import ( "context" "encoding/json" "fmt" + "io" "math/rand" "net" "os" @@ -27,6 +28,10 @@ import ( "sync" "time" + "github.com/aws/aws-sdk-go-v2/config" + + "github.com/aws/smithy-go" + "github.com/aws/amazon-vpc-cni-k8s/pkg/ipamd/datastore" "github.com/aws/amazon-vpc-cni-k8s/pkg/awsutils/awssession" @@ -36,10 +41,10 @@ import ( "github.com/aws/amazon-vpc-cni-k8s/pkg/utils/retry" "github.com/aws/amazon-vpc-cni-k8s/pkg/vpc" "github.com/aws/amazon-vpc-cni-k8s/utils/prometheusmetrics" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/ec2metadata" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/aws" + ec2metadata "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" + "github.com/aws/aws-sdk-go-v2/service/ec2" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" v1 "k8s.io/api/core/v1" @@ -74,6 +79,9 @@ const ( ) var ( + awsAPIError smithy.APIError + awsGenericAPIError *smithy.GenericAPIError + // ErrENINotFound is an error when ENI is not found. ErrENINotFound = errors.New("ENI is not found") // ErrAllSecondaryIPsNotFound is returned when not all secondary IPs on an ENI have been assigned @@ -101,13 +109,13 @@ type APIs interface { GetAttachedENIs() (eniList []ENIMetadata, err error) // GetIPv4sFromEC2 returns the IPv4 addresses for a given ENI - GetIPv4sFromEC2(eniID string) (addrList []*ec2.NetworkInterfacePrivateIpAddress, err error) + GetIPv4sFromEC2(eniID string) (addrList []ec2types.NetworkInterfacePrivateIpAddress, err error) // GetIPv4PrefixesFromEC2 returns the IPv4 prefixes for a given ENI - GetIPv4PrefixesFromEC2(eniID string) (addrList []*ec2.Ipv4PrefixSpecification, err error) + GetIPv4PrefixesFromEC2(eniID string) (addrList []ec2types.Ipv4PrefixSpecification, err error) // GetIPv6PrefixesFromEC2 returns the IPv6 prefixes for a given ENI - GetIPv6PrefixesFromEC2(eniID string) (addrList []*ec2.Ipv6PrefixSpecification, err error) + GetIPv6PrefixesFromEC2(eniID string) (addrList []ec2types.Ipv6PrefixSpecification, err error) // DescribeAllENIs calls EC2 and returns a fully populated DescribeAllENIsResult struct and an error DescribeAllENIs() (DescribeAllENIsResult, error) @@ -237,23 +245,23 @@ type ENIMetadata struct { SubnetIPv6CIDR string // The ip addresses allocated for the network interface - IPv4Addresses []*ec2.NetworkInterfacePrivateIpAddress + IPv4Addresses []ec2types.NetworkInterfacePrivateIpAddress // IPv4 Prefixes allocated for the network interface - IPv4Prefixes []*ec2.Ipv4PrefixSpecification + IPv4Prefixes []ec2types.Ipv4PrefixSpecification // IPv6 addresses allocated for the network interface - IPv6Addresses []*ec2.NetworkInterfaceIpv6Address + IPv6Addresses []ec2types.NetworkInterfaceIpv6Address // IPv6 Prefixes allocated for the network interface - IPv6Prefixes []*ec2.Ipv6PrefixSpecification + IPv6Prefixes []ec2types.Ipv6PrefixSpecification } // PrimaryIPv4Address returns the primary IPv4 address of this node func (eni ENIMetadata) PrimaryIPv4Address() string { for _, addr := range eni.IPv4Addresses { - if aws.BoolValue(addr.Primary) { - return aws.StringValue(addr.PrivateIpAddress) + if addr.Primary != nil && aws.ToBool(addr.Primary) { + return aws.ToString(addr.PrivateIpAddress) } } return "" @@ -263,7 +271,7 @@ func (eni ENIMetadata) PrimaryIPv4Address() string { func (eni ENIMetadata) PrimaryIPv6Address() string { for _, addr := range eni.IPv6Addresses { if addr.Ipv6Address != nil { - return aws.StringValue(addr.Ipv6Address) + return aws.ToString(addr.Ipv6Address) } } return "" @@ -332,16 +340,15 @@ func awsReqStatus(err error) string { if err == nil { return "200" } - var aerr awserr.RequestFailure - if errors.As(err, &aerr) { - return fmt.Sprint(aerr.StatusCode()) + if errors.As(err, &awsGenericAPIError) { + return fmt.Sprint(awsGenericAPIError.ErrorCode()) } return "" // Unknown HTTP status code } func (i instrumentedIMDS) GetMetadataWithContext(ctx context.Context, p string) (string, error) { start := time.Now() - result, err := i.EC2MetadataIface.GetMetadataWithContext(ctx, p) + output, err := i.EC2MetadataIface.GetMetadata(ctx, &ec2metadata.GetMetadataInput{Path: p}) duration := msSince(start) prometheusmetrics.AwsAPILatency.WithLabelValues("GetMetadata", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(duration) @@ -349,7 +356,14 @@ func (i instrumentedIMDS) GetMetadataWithContext(ctx context.Context, p string) if err != nil { return "", newIMDSRequestError(p, err) } - return result, nil + + defer output.Content.Close() + bytes, err := io.ReadAll(output.Content) + if err != nil { + return "", newIMDSRequestError(p, fmt.Errorf("failed to read content: %w", err)) + } + + return string(bytes), nil } // New creates an EC2InstanceMetadataCache @@ -357,19 +371,22 @@ func New(useSubnetDiscovery, useCustomNetworking, disableLeakedENICleanup, v4Ena // ctx is passed to initWithEC2Metadata func to cancel spawned go-routines when tests are run ctx := context.Background() - sess := awssession.New() - ec2Metadata := ec2metadata.New(sess) + awsconfig, err := awssession.New(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to create aws session") + } + ec2Metadata := ec2metadata.NewFromConfig(awsconfig) cache := &EC2InstanceMetadataCache{} cache.imds = TypedIMDS{instrumentedIMDS{ec2Metadata}} cache.clusterName = os.Getenv(clusterNameEnvVar) cache.additionalENITags = loadAdditionalENITags() - region, err := ec2Metadata.Region() + region, err := ec2Metadata.GetRegion(ctx, nil) if err != nil { log.Errorf("Failed to retrieve region data from instance metadata %v", err) return nil, errors.Wrap(err, "instance metadata: failed to retrieve region data") } - cache.region = region + cache.region = region.Region log.Debugf("Discovered region: %s", cache.region) cache.useCustomNetworking = useCustomNetworking log.Infof("Custom networking enabled %v", cache.useCustomNetworking) @@ -378,9 +395,11 @@ func New(useSubnetDiscovery, useCustomNetworking, disableLeakedENICleanup, v4Ena cache.v4Enabled = v4Enabled cache.v6Enabled = v6Enabled - awsCfg := aws.NewConfig().WithRegion(region) - sess = sess.Copy(awsCfg) - ec2SVC := ec2wrapper.New(sess) + awsCfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(region.Region)) + if err != nil { + return nil, fmt.Errorf("unable to load SDK config, %v", err) + } + ec2SVC := ec2wrapper.New(awsCfg) cache.ec2SVC = ec2SVC err = cache.initWithEC2Metadata(ctx) if err != nil { @@ -517,31 +536,31 @@ func (cache *EC2InstanceMetadataCache) RefreshSGIDs(mac string, store *datastore tempfilteredENIs := newENIs.Difference(&cache.multiCardENIs) filteredENIs := tempfilteredENIs.Difference(&cache.unmanagedENIs) - sgIDsPtrs := aws.StringSlice(sgIDs) // This will update SG for managed ENIs created by EKS. for _, eniID := range filteredENIs.SortedList() { log.Debugf("Update ENI %s", eniID) attributeInput := &ec2.ModifyNetworkInterfaceAttributeInput{ - Groups: sgIDsPtrs, + Groups: sgIDs, NetworkInterfaceId: aws.String(eniID), } start := time.Now() - _, err = cache.ec2SVC.ModifyNetworkInterfaceAttributeWithContext(context.Background(), attributeInput) + _, err = cache.ec2SVC.ModifyNetworkInterfaceAttribute(context.Background(), attributeInput) prometheusmetrics.Ec2ApiReq.WithLabelValues("ModifyNetworkInterfaceAttribute").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("ModifyNetworkInterfaceAttribute", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) + if err != nil { - if aerr, ok := err.(awserr.Error); ok { - if aerr.Code() == "InvalidNetworkInterfaceID.NotFound" { + if errors.As(err, &awsAPIError) { + if awsAPIError.ErrorCode() == "InvalidNetworkInterfaceID.NotFound" { awsAPIErrInc("IMDSMetaDataOutOfSync", err) } } checkAPIErrorAndBroadcastEvent(err, "ec2:ModifyNetworkInterfaceAttribute") awsAPIErrInc("ModifyNetworkInterfaceAttribute", err) prometheusmetrics.Ec2ApiErr.WithLabelValues("ModifyNetworkInterfaceAttribute").Inc() - //No need to return error here since retry will happen in 30seconds and also - //If update failed due to stale ENI then returning error will prevent updating SG - //for following ENIs since the list is sorted + // No need to return error here since retry will happen in 30 seconds and also + // If update failed due to stale ENI then returning error will prevent updating SG + // for following ENIs since the list is sorted log.Debugf("refreshSGIDs: unable to update the ENI %s SG - %v", eniID, err) } } @@ -610,7 +629,6 @@ func (cache *EC2InstanceMetadataCache) getENIMetadata(eniMAC string) (ENIMetadat awsAPIErrInc("GetMACImdsFields", err) return ENIMetadata{}, err } - ipv4Available := false ipv6Available := false // Efa-only interfaces do not have any ipv4s or ipv6s associated with it. If we don't find any local-ipv4 or ipv6 info in imds we assume it to be efa-only interface and validate this later via ec2 call @@ -645,16 +663,16 @@ func (cache *EC2InstanceMetadataCache) getENIMetadata(eniMAC string) (ENIMetadat MAC: eniMAC, DeviceNumber: deviceNum, SubnetIPv4CIDR: "", - IPv4Addresses: make([]*ec2.NetworkInterfacePrivateIpAddress, 0), - IPv4Prefixes: make([]*ec2.Ipv4PrefixSpecification, 0), + IPv4Addresses: make([]ec2types.NetworkInterfacePrivateIpAddress, 0), + IPv4Prefixes: make([]ec2types.Ipv4PrefixSpecification, 0), SubnetIPv6CIDR: "", - IPv6Addresses: make([]*ec2.NetworkInterfaceIpv6Address, 0), - IPv6Prefixes: make([]*ec2.Ipv6PrefixSpecification, 0), + IPv6Addresses: make([]ec2types.NetworkInterfaceIpv6Address, 0), + IPv6Prefixes: make([]ec2types.Ipv6PrefixSpecification, 0), }, nil } // Get IPv4 and IPv6 addresses assigned to interface - var ec2ip4s []*ec2.NetworkInterfacePrivateIpAddress + var ec2ip4s []ec2types.NetworkInterfacePrivateIpAddress var subnetV4Cidr string if ipv4Available { cidr, err := cache.imds.GetSubnetIPv4CIDRBlock(ctx, eniMAC) @@ -671,16 +689,16 @@ func (cache *EC2InstanceMetadataCache) getENIMetadata(eniMAC string) (ENIMetadat return ENIMetadata{}, err } - ec2ip4s = make([]*ec2.NetworkInterfacePrivateIpAddress, len(imdsIPv4s)) + ec2ip4s = make([]ec2types.NetworkInterfacePrivateIpAddress, len(imdsIPv4s)) for i, ip4 := range imdsIPv4s { - ec2ip4s[i] = &ec2.NetworkInterfacePrivateIpAddress{ + ec2ip4s[i] = ec2types.NetworkInterfacePrivateIpAddress{ Primary: aws.Bool(i == 0), PrivateIpAddress: aws.String(ip4.String()), } } } - var ec2ip6s []*ec2.NetworkInterfaceIpv6Address + var ec2ip6s []ec2types.NetworkInterfaceIpv6Address var subnetV6Cidr string if cache.v6Enabled { // For IPv6 ENIs, do not error on missing IPv6 information @@ -695,17 +713,17 @@ func (cache *EC2InstanceMetadataCache) getENIMetadata(eniMAC string) (ENIMetadat if err != nil { awsAPIErrInc("GetIPv6s", err) } else { - ec2ip6s = make([]*ec2.NetworkInterfaceIpv6Address, len(imdsIPv6s)) + ec2ip6s = make([]ec2types.NetworkInterfaceIpv6Address, len(imdsIPv6s)) for i, ip6 := range imdsIPv6s { - ec2ip6s[i] = &ec2.NetworkInterfaceIpv6Address{ + ec2ip6s[i] = ec2types.NetworkInterfaceIpv6Address{ Ipv6Address: aws.String(ip6.String()), } } } } - var ec2ipv4Prefixes []*ec2.Ipv4PrefixSpecification - var ec2ipv6Prefixes []*ec2.Ipv6PrefixSpecification + var ec2ipv4Prefixes []ec2types.Ipv4PrefixSpecification + var ec2ipv6Prefixes []ec2types.Ipv6PrefixSpecification // If IPv6 is enabled, get attached v6 prefixes. if cache.v6Enabled { @@ -715,7 +733,7 @@ func (cache *EC2InstanceMetadataCache) getENIMetadata(eniMAC string) (ENIMetadat return ENIMetadata{}, err } for _, ipv6prefix := range imdsIPv6Prefixes { - ec2ipv6Prefixes = append(ec2ipv6Prefixes, &ec2.Ipv6PrefixSpecification{ + ec2ipv6Prefixes = append(ec2ipv6Prefixes, ec2types.Ipv6PrefixSpecification{ Ipv6Prefix: aws.String(ipv6prefix.String()), }) } @@ -730,7 +748,7 @@ func (cache *EC2InstanceMetadataCache) getENIMetadata(eniMAC string) (ENIMetadat return ENIMetadata{}, err } for _, ipv4prefix := range imdsIPv4Prefixes { - ec2ipv4Prefixes = append(ec2ipv4Prefixes, &ec2.Ipv4PrefixSpecification{ + ec2ipv4Prefixes = append(ec2ipv4Prefixes, ec2types.Ipv4PrefixSpecification{ Ipv4Prefix: aws.String(ipv4prefix.String()), }) } @@ -752,11 +770,11 @@ func (cache *EC2InstanceMetadataCache) getENIMetadata(eniMAC string) (ENIMetadat // awsGetFreeDeviceNumber calls EC2 API DescribeInstances to get the next free device index func (cache *EC2InstanceMetadataCache) awsGetFreeDeviceNumber() (int, error) { input := &ec2.DescribeInstancesInput{ - InstanceIds: []*string{aws.String(cache.instanceID)}, + InstanceIds: []string{cache.instanceID}, } start := time.Now() - result, err := cache.ec2SVC.DescribeInstancesWithContext(context.Background(), input) + result, err := cache.ec2SVC.DescribeInstances(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("DescribeInstances").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("DescribeInstances", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { @@ -776,14 +794,14 @@ func (cache *EC2InstanceMetadataCache) awsGetFreeDeviceNumber() (int, error) { var device [maxENIs]bool for _, eni := range inst.NetworkInterfaces { // We don't support multi-card yet, so only account for network card zero - if aws.Int64Value(eni.Attachment.NetworkCardIndex) == 0 { - if aws.Int64Value(eni.Attachment.DeviceIndex) > maxENIs { + if eni.Attachment != nil && aws.ToInt32(eni.Attachment.NetworkCardIndex) == 0 { + if aws.ToInt32(eni.Attachment.DeviceIndex) > maxENIs { log.Warnf("The Device Index %d of the attached ENI %s > instance max slot %d", - aws.Int64Value(eni.Attachment.DeviceIndex), aws.StringValue(eni.NetworkInterfaceId), + aws.ToInt32(eni.Attachment.DeviceIndex), aws.ToString(eni.NetworkInterfaceId), maxENIs) } else { - log.Debugf("Discovered device number is used: %d", aws.Int64Value(eni.Attachment.DeviceIndex)) - device[aws.Int64Value(eni.Attachment.DeviceIndex)] = true + log.Debugf("Discovered device number is used: %d", aws.ToInt32(eni.Attachment.DeviceIndex)) + device[aws.ToInt32(eni.Attachment.DeviceIndex)] = true } } } @@ -817,7 +835,7 @@ func (cache *EC2InstanceMetadataCache) AllocENI(useCustomCfg bool, sg []*string, // Also change the ENI's attribute so that the ENI will be deleted when the instance is deleted. attributeInput := &ec2.ModifyNetworkInterfaceAttributeInput{ - Attachment: &ec2.NetworkInterfaceAttachmentChanges{ + Attachment: &ec2types.NetworkInterfaceAttachmentChanges{ AttachmentId: aws.String(attachmentID), DeleteOnTermination: aws.Bool(true), }, @@ -825,7 +843,7 @@ func (cache *EC2InstanceMetadataCache) AllocENI(useCustomCfg bool, sg []*string, } start := time.Now() - _, err = cache.ec2SVC.ModifyNetworkInterfaceAttributeWithContext(context.Background(), attributeInput) + _, err = cache.ec2SVC.ModifyNetworkInterfaceAttribute(context.Background(), attributeInput) prometheusmetrics.Ec2ApiReq.WithLabelValues("ModifyNetworkInterfaceAttribute").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("ModifyNetworkInterfaceAttribute", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { @@ -852,13 +870,13 @@ func (cache *EC2InstanceMetadataCache) attachENI(eniID string) (string, error) { } attachInput := &ec2.AttachNetworkInterfaceInput{ - DeviceIndex: aws.Int64(int64(freeDevice)), + DeviceIndex: aws.Int32(int32(freeDevice)), InstanceId: aws.String(cache.instanceID), NetworkInterfaceId: aws.String(eniID), - NetworkCardIndex: aws.Int64(0), + NetworkCardIndex: aws.Int32(0), } start := time.Now() - attachOutput, err := cache.ec2SVC.AttachNetworkInterfaceWithContext(context.Background(), attachInput) + attachOutput, err := cache.ec2SVC.AttachNetworkInterface(context.Background(), attachInput) prometheusmetrics.Ec2ApiReq.WithLabelValues("AttachNetworkInterface").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("AttachNetworkInterface", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { @@ -868,7 +886,7 @@ func (cache *EC2InstanceMetadataCache) attachENI(eniID string) (string, error) { log.Errorf("Failed to attach ENI %s: %v", eniID, err) return "", errors.Wrap(err, "attachENI: failed to attach ENI") } - return aws.StringValue(attachOutput.AttachmentId), err + return aws.ToString(attachOutput.AttachmentId), err } // return ENI id, error @@ -880,9 +898,9 @@ func (cache *EC2InstanceMetadataCache) createENI(useCustomCfg bool, sg []*string for key, value := range cache.buildENITags() { tags[key] = value } - tagSpec := []*ec2.TagSpecification{ + tagSpec := []ec2types.TagSpecification{ { - ResourceType: aws.String(ec2.ResourceTypeNetworkInterface), + ResourceType: ec2types.ResourceTypeNetworkInterface, Tags: convertTagsToSDKTags(tags), }, } @@ -901,18 +919,18 @@ func (cache *EC2InstanceMetadataCache) createENI(useCustomCfg bool, sg []*string if cache.enablePrefixDelegation { input = &ec2.CreateNetworkInterfaceInput{ Description: aws.String(eniDescription), - Groups: aws.StringSlice(cache.securityGroups.SortedList()), + Groups: cache.securityGroups.SortedList(), SubnetId: aws.String(cache.subnetID), TagSpecifications: tagSpec, - Ipv4PrefixCount: aws.Int64(int64(needIPs)), + Ipv4PrefixCount: aws.Int32(int32(needIPs)), } } else { input = &ec2.CreateNetworkInterfaceInput{ Description: aws.String(eniDescription), - Groups: aws.StringSlice(cache.securityGroups.SortedList()), + Groups: cache.securityGroups.SortedList(), SubnetId: aws.String(cache.subnetID), TagSpecifications: tagSpec, - SecondaryPrivateIpAddressCount: aws.Int64(int64(needIPs)), + SecondaryPrivateIpAddressCount: aws.Int32(int32(needIPs)), } } @@ -920,7 +938,7 @@ func (cache *EC2InstanceMetadataCache) createENI(useCustomCfg bool, sg []*string var networkInterfaceID string if cache.useCustomNetworking { input = createENIUsingCustomCfg(sg, eniCfgSubnet, input) - log.Infof("Creating ENI with security groups: %v in subnet: %s", aws.StringValueSlice(input.Groups), aws.StringValue(input.SubnetId)) + log.Infof("Creating ENI with security groups: %v in subnet: %s", input.Groups, aws.ToString(input.SubnetId)) networkInterfaceID, err = cache.tryCreateNetworkInterface(input) if err == nil { @@ -943,7 +961,7 @@ func (cache *EC2InstanceMetadataCache) createENI(useCustomCfg bool, sg []*string continue } } - log.Infof("Creating ENI with security groups: %v in subnet: %s", aws.StringValueSlice(input.Groups), aws.StringValue(input.SubnetId)) + log.Infof("Creating ENI with security groups: %v in subnet: %s", input.Groups, aws.ToString(input.SubnetId)) input.SubnetId = subnet.SubnetId networkInterfaceID, err = cache.tryCreateNetworkInterface(input) @@ -963,22 +981,22 @@ func (cache *EC2InstanceMetadataCache) createENI(useCustomCfg bool, sg []*string return "", errors.Wrap(err, "failed to create network interface") } -func (cache *EC2InstanceMetadataCache) getVpcSubnets() ([]*ec2.Subnet, error) { +func (cache *EC2InstanceMetadataCache) getVpcSubnets() ([]ec2types.Subnet, error) { describeSubnetInput := &ec2.DescribeSubnetsInput{ - Filters: []*ec2.Filter{ + Filters: []ec2types.Filter{ { Name: aws.String("vpc-id"), - Values: []*string{aws.String(cache.vpcID)}, + Values: []string{cache.vpcID}, }, { Name: aws.String("availability-zone"), - Values: []*string{aws.String(cache.availabilityZone)}, + Values: []string{cache.availabilityZone}, }, }, } start := time.Now() - subnetResult, err := cache.ec2SVC.DescribeSubnetsWithContext(context.Background(), describeSubnetInput) + subnetResult, err := cache.ec2SVC.DescribeSubnets(context.Background(), describeSubnetInput) prometheusmetrics.Ec2ApiReq.WithLabelValues("DescribeSubnets").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("DescribeSubnets", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { @@ -996,7 +1014,7 @@ func (cache *EC2InstanceMetadataCache) getVpcSubnets() ([]*ec2.Subnet, error) { return subnetResult.Subnets, nil } -func validTag(subnet *ec2.Subnet) bool { +func validTag(subnet ec2types.Subnet) bool { for _, tag := range subnet.Tags { if *tag.Key == subnetDiscoveryTagKey { return true @@ -1009,9 +1027,9 @@ func createENIUsingCustomCfg(sg []*string, eniCfgSubnet string, input *ec2.Creat log.Info("Using a custom network config for the new ENI") if len(sg) != 0 { - input.Groups = sg + input.Groups = aws.ToStringSlice(sg) } else { - log.Warnf("No custom networking security group found, will use the node's primary ENI's SG: %v", aws.StringValueSlice(input.Groups)) + log.Warnf("No custom networking security group found, will use the node's primary ENI's SG: %v", input.Groups) } input.SubnetId = aws.String(eniCfgSubnet) @@ -1020,12 +1038,12 @@ func createENIUsingCustomCfg(sg []*string, eniCfgSubnet string, input *ec2.Creat func (cache *EC2InstanceMetadataCache) tryCreateNetworkInterface(input *ec2.CreateNetworkInterfaceInput) (string, error) { start := time.Now() - result, err := cache.ec2SVC.CreateNetworkInterfaceWithContext(context.Background(), input) + result, err := cache.ec2SVC.CreateNetworkInterface(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("CreateNetworkInterface").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("CreateNetworkInterface", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err == nil { - log.Infof("Created a new ENI: %s", aws.StringValue(result.NetworkInterface.NetworkInterfaceId)) - return aws.StringValue(result.NetworkInterface.NetworkInterfaceId), nil + log.Infof("Created a new ENI: %s", aws.ToString(result.NetworkInterface.NetworkInterfaceId)) + return aws.ToString(result.NetworkInterface.NetworkInterfaceId), nil } checkAPIErrorAndBroadcastEvent(err, "ec2:CreateNetworkInterface") awsAPIErrInc("CreateNetworkInterface", err) @@ -1063,16 +1081,14 @@ func (cache *EC2InstanceMetadataCache) TagENI(eniID string, currentTags map[stri } input := &ec2.CreateTagsInput{ - Resources: []*string{ - aws.String(eniID), - }, - Tags: convertTagsToSDKTags(tagChanges), + Resources: []string{eniID}, + Tags: convertTagsToSDKTags(tagChanges), } log.Debugf("Tagging ENI %s with missing tags: %v", eniID, tagChanges) return retry.NWithBackoff(retry.NewSimpleBackoff(500*time.Millisecond, maxENIBackoffDelay, 0.3, 2), 5, func() error { start := time.Now() - _, err := cache.ec2SVC.CreateTagsWithContext(context.Background(), input) + _, err := cache.ec2SVC.CreateTags(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("CreateTags").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("CreateTags", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { @@ -1088,13 +1104,15 @@ func (cache *EC2InstanceMetadataCache) TagENI(eniID string, currentTags map[stri } func awsAPIErrInc(api string, err error) { - if aerr, ok := err.(awserr.Error); ok { - prometheusmetrics.AwsAPIErr.With(prometheus.Labels{"api": api, "error": aerr.Code()}).Inc() + if errors.As(err, &awsAPIError) { + prometheusmetrics.AwsAPIErr.With(prometheus.Labels{"api": api, "error": awsAPIError.ErrorCode()}).Inc() } } func awsUtilsErrInc(fn string, err error) { - prometheusmetrics.AwsUtilsErr.With(prometheus.Labels{"fn": fn, "error": err.Error()}).Inc() + if errors.As(err, &awsAPIError) { + prometheusmetrics.AwsUtilsErr.With(prometheus.Labels{"fn": fn, "error": err.Error()}).Inc() + } } // FreeENI detaches and deletes the ENI interface @@ -1116,7 +1134,7 @@ func (cache *EC2InstanceMetadataCache) freeENI(eniName string, sleepDelayAfterDe log.Errorf("Failed to retrieve ENI %s attachment id: %v", eniName, err) return errors.Wrap(err, "FreeENI: failed to retrieve ENI's attachment id") } - log.Debugf("Found ENI %s attachment id: %s ", eniName, aws.StringValue(attachID)) + log.Debugf("Found ENI %s attachment id: %s ", eniName, aws.ToString(attachID)) detachInput := &ec2.DetachNetworkInterfaceInput{ AttachmentId: attachID, @@ -1125,7 +1143,7 @@ func (cache *EC2InstanceMetadataCache) freeENI(eniName string, sleepDelayAfterDe // Retry detaching the ENI from the instance err = retry.NWithBackoff(retry.NewSimpleBackoff(time.Millisecond*200, maxBackoffDelay, 0.15, 2.0), maxENIEC2APIRetries, func() error { start := time.Now() - _, ec2Err := cache.ec2SVC.DetachNetworkInterfaceWithContext(context.Background(), detachInput) + _, ec2Err := cache.ec2SVC.DetachNetworkInterface(context.Background(), detachInput) prometheusmetrics.Ec2ApiReq.WithLabelValues("DetachNetworkInterface").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("DetachNetworkInterface", fmt.Sprint(ec2Err != nil), awsReqStatus(ec2Err)).Observe(msSince(start)) if ec2Err != nil { @@ -1160,15 +1178,15 @@ func (cache *EC2InstanceMetadataCache) freeENI(eniName string, sleepDelayAfterDe func (cache *EC2InstanceMetadataCache) getENIAttachmentID(eniID string) (*string, error) { eniIds := make([]*string, 0) eniIds = append(eniIds, aws.String(eniID)) - input := &ec2.DescribeNetworkInterfacesInput{NetworkInterfaceIds: eniIds} + input := &ec2.DescribeNetworkInterfacesInput{NetworkInterfaceIds: aws.ToStringSlice(eniIds)} start := time.Now() - result, err := cache.ec2SVC.DescribeNetworkInterfacesWithContext(context.Background(), input) + result, err := cache.ec2SVC.DescribeNetworkInterfaces(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("DescribeNetworkInterfaces").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("DescribeNetworkInterfaces", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - if aerr.Code() == "InvalidNetworkInterfaceID.NotFound" { + if errors.As(err, &awsAPIError) { + if awsAPIError.ErrorCode() == "InvalidNetworkInterfaceID.NotFound" { return nil, ErrENINotFound } } @@ -1201,13 +1219,13 @@ func (cache *EC2InstanceMetadataCache) deleteENI(eniName string, maxBackoffDelay } err := retry.NWithBackoff(retry.NewSimpleBackoff(time.Millisecond*500, maxBackoffDelay, 0.15, 2.0), maxENIEC2APIRetries, func() error { start := time.Now() - _, ec2Err := cache.ec2SVC.DeleteNetworkInterfaceWithContext(context.Background(), deleteInput) + _, ec2Err := cache.ec2SVC.DeleteNetworkInterface(context.Background(), deleteInput) prometheusmetrics.Ec2ApiReq.WithLabelValues("DeleteNetworkInterface").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("DeleteNetworkInterface", fmt.Sprint(ec2Err != nil), awsReqStatus(ec2Err)).Observe(msSince(start)) if ec2Err != nil { - if aerr, ok := ec2Err.(awserr.Error); ok { + if errors.As(ec2Err, &awsAPIError) { // If already deleted, we are good - if aerr.Code() == "InvalidNetworkInterfaceID.NotFound" { + if awsAPIError.ErrorCode() == "InvalidNetworkInterfaceID.NotFound" { log.Infof("ENI %s has already been deleted", eniName) return nil } @@ -1225,18 +1243,18 @@ func (cache *EC2InstanceMetadataCache) deleteENI(eniName string, maxBackoffDelay } // GetIPv4sFromEC2 calls EC2 and returns a list of all addresses on the ENI -func (cache *EC2InstanceMetadataCache) GetIPv4sFromEC2(eniID string) (addrList []*ec2.NetworkInterfacePrivateIpAddress, err error) { +func (cache *EC2InstanceMetadataCache) GetIPv4sFromEC2(eniID string) (addrList []ec2types.NetworkInterfacePrivateIpAddress, err error) { eniIds := make([]*string, 0) eniIds = append(eniIds, aws.String(eniID)) - input := &ec2.DescribeNetworkInterfacesInput{NetworkInterfaceIds: eniIds} + input := &ec2.DescribeNetworkInterfacesInput{NetworkInterfaceIds: aws.ToStringSlice(eniIds)} start := time.Now() - result, err := cache.ec2SVC.DescribeNetworkInterfacesWithContext(context.Background(), input) + result, err := cache.ec2SVC.DescribeNetworkInterfaces(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("DescribeNetworkInterfaces").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("DescribeNetworkInterfaces", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - if aerr.Code() == "InvalidNetworkInterfaceID.NotFound" { + if errors.As(err, &awsAPIError) { + if awsAPIError.ErrorCode() == "InvalidNetworkInterfaceID.NotFound" { return nil, ErrENINotFound } } @@ -1257,17 +1275,17 @@ func (cache *EC2InstanceMetadataCache) GetIPv4sFromEC2(eniID string) (addrList [ } // GetIPv4PrefixesFromEC2 calls EC2 and returns a list of all addresses on the ENI -func (cache *EC2InstanceMetadataCache) GetIPv4PrefixesFromEC2(eniID string) (addrList []*ec2.Ipv4PrefixSpecification, err error) { +func (cache *EC2InstanceMetadataCache) GetIPv4PrefixesFromEC2(eniID string) (addrList []ec2types.Ipv4PrefixSpecification, err error) { eniIds := []*string{aws.String(eniID)} - input := &ec2.DescribeNetworkInterfacesInput{NetworkInterfaceIds: eniIds} + input := &ec2.DescribeNetworkInterfacesInput{NetworkInterfaceIds: aws.ToStringSlice(eniIds)} start := time.Now() - result, err := cache.ec2SVC.DescribeNetworkInterfacesWithContext(context.Background(), input) + result, err := cache.ec2SVC.DescribeNetworkInterfaces(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("DescribeNetworkInterfaces").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("DescribeNetworkInterfaces", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - if aerr.Code() == "InvalidNetworkInterfaceID.NotFound" { + if errors.As(err, &awsAPIError) { + if awsAPIError.ErrorCode() == "InvalidNetworkInterfaceID.NotFound" { return nil, ErrENINotFound } @@ -1289,17 +1307,17 @@ func (cache *EC2InstanceMetadataCache) GetIPv4PrefixesFromEC2(eniID string) (add } // GetIPv6PrefixesFromEC2 calls EC2 and returns a list of all addresses on the ENI -func (cache *EC2InstanceMetadataCache) GetIPv6PrefixesFromEC2(eniID string) (addrList []*ec2.Ipv6PrefixSpecification, err error) { +func (cache *EC2InstanceMetadataCache) GetIPv6PrefixesFromEC2(eniID string) (addrList []ec2types.Ipv6PrefixSpecification, err error) { eniIds := []*string{aws.String(eniID)} - input := &ec2.DescribeNetworkInterfacesInput{NetworkInterfaceIds: eniIds} + input := &ec2.DescribeNetworkInterfacesInput{NetworkInterfaceIds: aws.ToStringSlice(eniIds)} start := time.Now() - result, err := cache.ec2SVC.DescribeNetworkInterfacesWithContext(context.Background(), input) + result, err := cache.ec2SVC.DescribeNetworkInterfaces(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("DescribeNetworkInterfaces").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("DescribeNetworkInterfaces", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - if aerr.Code() == "InvalidNetworkInterfaceID.NotFound" { + if errors.As(err, &awsAPIError) { + if awsAPIError.ErrorCode() == "InvalidNetworkInterfaceID.NotFound" { return nil, ErrENINotFound } @@ -1337,9 +1355,9 @@ func (cache *EC2InstanceMetadataCache) DescribeAllENIs() (DescribeAllENIsResult, var ec2Response *ec2.DescribeNetworkInterfacesOutput // Try calling EC2 to describe the interfaces. for retryCount := 0; retryCount < maxENIEC2APIRetries && len(eniIDs) > 0; retryCount++ { - input := &ec2.DescribeNetworkInterfacesInput{NetworkInterfaceIds: aws.StringSlice(eniIDs)} + input := &ec2.DescribeNetworkInterfacesInput{NetworkInterfaceIds: eniIDs} start := time.Now() - ec2Response, err = cache.ec2SVC.DescribeNetworkInterfacesWithContext(context.Background(), input) + ec2Response, err = cache.ec2SVC.DescribeNetworkInterfaces(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("DescribeNetworkInterfaces").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("DescribeNetworkInterfaces", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err == nil { @@ -1349,11 +1367,12 @@ func (cache *EC2InstanceMetadataCache) DescribeAllENIs() (DescribeAllENIsResult, awsAPIErrInc("DescribeNetworkInterfaces", err) prometheusmetrics.Ec2ApiErr.WithLabelValues("DescribeNetworkInterfaces").Inc() checkAPIErrorAndBroadcastEvent(err, "ec2:DescribeNetworkInterfaces") - log.Errorf("Failed to call ec2:DescribeNetworkInterfaces for %v: %v", aws.StringValueSlice(input.NetworkInterfaceIds), err) - if aerr, ok := err.(awserr.Error); ok { - if aerr.Code() == "InvalidNetworkInterfaceID.NotFound" { - badENIID := badENIID(aerr.Message()) - log.Debugf("Could not find interface: %s, ID: %s", aerr.Message(), badENIID) + log.Errorf("Failed to call ec2:DescribeNetworkInterfaces for %v: %v", input.NetworkInterfaceIds, err) + if errors.As(err, &awsAPIError) { + log.Debugf("Failed ec2:DescribeNetworkInterfaces awsAPIError ErrorCode :%v ErrorMessage: %v", awsAPIError.ErrorCode(), awsAPIError.ErrorMessage()) + if awsAPIError.ErrorCode() == "InvalidNetworkInterfaceID.NotFound" { + badENIID := badENIID(awsAPIError.ErrorMessage()) + log.Debugf("Could not find interface: %s, ID: %s", awsAPIError.ErrorMessage(), badENIID) awsAPIErrInc("IMDSMetaDataOutOfSync", err) // Remove this ENI from the map delete(eniMap, badENIID) @@ -1388,15 +1407,15 @@ func (cache *EC2InstanceMetadataCache) DescribeAllENIs() (DescribeAllENIsResult, efaENIs := make(map[string]bool, 0) tagMap := make(map[string]TagMap, len(ec2Response.NetworkInterfaces)) for _, ec2res := range ec2Response.NetworkInterfaces { - eniID := aws.StringValue(ec2res.NetworkInterfaceId) + eniID := aws.ToString(ec2res.NetworkInterfaceId) attachment := ec2res.Attachment // Validate that Attachment is populated by EC2 response before logging if attachment != nil { - log.Infof("Got network card index %v for ENI %v", aws.Int64Value(attachment.NetworkCardIndex), eniID) - if aws.Int64Value(attachment.DeviceIndex) == 0 && !aws.BoolValue(attachment.DeleteOnTermination) { + log.Infof("Got network card index %v for ENI %v", aws.ToInt32(attachment.NetworkCardIndex), eniID) + if aws.ToInt32(attachment.DeviceIndex) == 0 && !aws.ToBool(attachment.DeleteOnTermination) { log.Warn("Primary ENI will not get deleted when node terminates because 'delete_on_termination' is set to false") } - if aws.Int64Value(attachment.NetworkCardIndex) > 0 { + if aws.ToInt32(attachment.NetworkCardIndex) > 0 { multiCardENIIDs = append(multiCardENIIDs, eniID) } } else { @@ -1404,7 +1423,7 @@ func (cache *EC2InstanceMetadataCache) DescribeAllENIs() (DescribeAllENIsResult, } eniMetadata := eniMap[eniID] - interfaceType := aws.StringValue(ec2res.InterfaceType) + interfaceType := ec2res.InterfaceType log.Infof("%s is of type: %s", eniID, interfaceType) // This assumes we only have one trunk attached to the node.. @@ -1438,14 +1457,14 @@ func (cache *EC2InstanceMetadataCache) DescribeAllENIs() (DescribeAllENIsResult, } // convertTagsToSDKTags converts tags in stringMap format to AWS SDK format -func convertTagsToSDKTags(tagsMap map[string]string) []*ec2.Tag { +func convertTagsToSDKTags(tagsMap map[string]string) []ec2types.Tag { if len(tagsMap) == 0 { return nil } - sdkTags := make([]*ec2.Tag, 0, len(tagsMap)) + sdkTags := make([]ec2types.Tag, 0, len(tagsMap)) for _, key := range sets.StringKeySet(tagsMap).List() { - sdkTags = append(sdkTags, &ec2.Tag{ + sdkTags = append(sdkTags, ec2types.Tag{ Key: aws.String(key), Value: aws.String(tagsMap[key]), }) @@ -1454,14 +1473,14 @@ func convertTagsToSDKTags(tagsMap map[string]string) []*ec2.Tag { } // convertSDKTagsToTags converts tags in AWS SDKs format to stringMap format -func convertSDKTagsToTags(sdkTags []*ec2.Tag) map[string]string { +func convertSDKTagsToTags(sdkTags []ec2types.Tag) map[string]string { if len(sdkTags) == 0 { return nil } tagsMap := make(map[string]string, len(sdkTags)) for _, sdkTag := range sdkTags { - tagsMap[aws.StringValue(sdkTag.Key)] = aws.StringValue(sdkTag.Value) + tagsMap[aws.ToString(sdkTag.Key)] = aws.ToString(sdkTag.Value) } return tagsMap } @@ -1503,24 +1522,24 @@ func badENIID(errMsg string) string { } // logOutOfSyncState compares the IP and metadata returned by IMDS and the EC2 API DescribeNetworkInterfaces calls -func logOutOfSyncState(eniID string, imdsIPv4s, ec2IPv4s []*ec2.NetworkInterfacePrivateIpAddress) { +func logOutOfSyncState(eniID string, imdsIPv4s, ec2IPv4s []ec2types.NetworkInterfacePrivateIpAddress) { // Comparing the IMDS IPv4 addresses attached to the ENI with the DescribeNetworkInterfaces AWS API call, which // technically should be the source of truth and contain the freshest information. Let's just do a quick scan here // and output some diagnostic messages if we find stale info in the IMDS result. imdsIPv4Set := sets.String{} imdsPrimaryIP := "" for _, imdsIPv4 := range imdsIPv4s { - imdsIPv4Set.Insert(aws.StringValue(imdsIPv4.PrivateIpAddress)) - if aws.BoolValue(imdsIPv4.Primary) { - imdsPrimaryIP = aws.StringValue(imdsIPv4.PrivateIpAddress) + imdsIPv4Set.Insert(aws.ToString(imdsIPv4.PrivateIpAddress)) + if aws.ToBool(imdsIPv4.Primary) { + imdsPrimaryIP = aws.ToString(imdsIPv4.PrivateIpAddress) } } ec2IPv4Set := sets.String{} ec2IPv4PrimaryIP := "" for _, privateIPv4 := range ec2IPv4s { - ec2IPv4Set.Insert(aws.StringValue(privateIPv4.PrivateIpAddress)) - if aws.BoolValue(privateIPv4.Primary) { - ec2IPv4PrimaryIP = aws.StringValue(privateIPv4.PrivateIpAddress) + ec2IPv4Set.Insert(aws.ToString(privateIPv4.PrivateIpAddress)) + if aws.ToBool(privateIPv4.Primary) { + ec2IPv4PrimaryIP = aws.ToString(privateIPv4.PrivateIpAddress) } } missingIMDS := ec2IPv4Set.Difference(imdsIPv4Set).List() @@ -1544,11 +1563,11 @@ func (cache *EC2InstanceMetadataCache) AllocIPAddress(eniID string) error { input := &ec2.AssignPrivateIpAddressesInput{ NetworkInterfaceId: aws.String(eniID), - SecondaryPrivateIpAddressCount: aws.Int64(1), + SecondaryPrivateIpAddressCount: aws.Int32(1), } start := time.Now() - output, err := cache.ec2SVC.AssignPrivateIpAddressesWithContext(context.Background(), input) + output, err := cache.ec2SVC.AssignPrivateIpAddresses(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("AssignPrivateIpAddresses").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("AssignPrivateIpAddresses", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { @@ -1559,7 +1578,7 @@ func (cache *EC2InstanceMetadataCache) AllocIPAddress(eniID string) error { return errors.Wrap(err, "failed to assign private IP addresses") } - log.Infof("Successfully allocated IP address %s on ENI %s", output.String(), eniID) + log.Infof("Successfully allocated IP address %v on ENI %s", output.AssignedPrivateIpAddresses, eniID) return nil } @@ -1570,8 +1589,8 @@ func (cache *EC2InstanceMetadataCache) FetchInstanceTypeLimits() error { } log.Debugf("Instance type limits are missing from vpc_ip_limits.go hence making an EC2 call to fetch the limits") - describeInstanceTypesInput := &ec2.DescribeInstanceTypesInput{InstanceTypes: []*string{aws.String(cache.instanceType)}} - output, err := cache.ec2SVC.DescribeInstanceTypesWithContext(context.Background(), describeInstanceTypesInput) + describeInstanceTypesInput := &ec2.DescribeInstanceTypesInput{InstanceTypes: []ec2types.InstanceType{ec2types.InstanceType(cache.instanceType)}} + output, err := cache.ec2SVC.DescribeInstanceTypes(context.Background(), describeInstanceTypesInput) prometheusmetrics.Ec2ApiReq.WithLabelValues("DescribeInstanceTypes").Inc() if err != nil || len(output.InstanceTypes) != 1 { prometheusmetrics.Ec2ApiErr.WithLabelValues("DescribeInstanceTypes").Inc() @@ -1580,20 +1599,20 @@ func (cache *EC2InstanceMetadataCache) FetchInstanceTypeLimits() error { } info := output.InstanceTypes[0] // Ignore any missing values - instanceType := aws.StringValue(info.InstanceType) - eniLimit := int(aws.Int64Value(info.NetworkInfo.MaximumNetworkInterfaces)) - ipv4Limit := int(aws.Int64Value(info.NetworkInfo.Ipv4AddressesPerInterface)) - isBareMetalInstance := aws.BoolValue(info.BareMetal) - hypervisorType := aws.StringValue(info.Hypervisor) + instanceType := info.InstanceType + eniLimit := int(aws.ToInt32(info.NetworkInfo.MaximumNetworkInterfaces)) + ipv4Limit := int(aws.ToInt32(info.NetworkInfo.Ipv4AddressesPerInterface)) + isBareMetalInstance := aws.ToBool(info.BareMetal) + hypervisorType := info.Hypervisor if hypervisorType == "" { hypervisorType = "unknown" } - networkCards := make([]vpc.NetworkCard, aws.Int64Value(info.NetworkInfo.MaximumNetworkCards)) - defaultNetworkCardIndex := int(aws.Int64Value(info.NetworkInfo.DefaultNetworkCardIndex)) + networkCards := make([]vpc.NetworkCard, aws.ToInt32(info.NetworkInfo.MaximumNetworkCards)) + defaultNetworkCardIndex := int(aws.ToInt32(info.NetworkInfo.DefaultNetworkCardIndex)) for idx := 0; idx < len(networkCards); idx += 1 { networkCards[idx] = vpc.NetworkCard{ - MaximumNetworkInterfaces: *info.NetworkInfo.NetworkCards[idx].MaximumNetworkInterfaces, - NetworkCardIndex: *info.NetworkInfo.NetworkCards[idx].NetworkCardIndex, + MaximumNetworkInterfaces: int64(*info.NetworkInfo.NetworkCards[idx].MaximumNetworkInterfaces), + NetworkCardIndex: int64(*info.NetworkInfo.NetworkCards[idx].NetworkCardIndex), } } //Not checking for empty hypervisorType since have seen certain instances not getting this filled. @@ -1691,18 +1710,18 @@ func (cache *EC2InstanceMetadataCache) AllocIPAddresses(eniID string, numIPs int needPrefixes := needIPs input = &ec2.AssignPrivateIpAddressesInput{ NetworkInterfaceId: aws.String(eniID), - Ipv4PrefixCount: aws.Int64(int64(needPrefixes)), + Ipv4PrefixCount: aws.Int32(int32(needPrefixes)), } } else { input = &ec2.AssignPrivateIpAddressesInput{ NetworkInterfaceId: aws.String(eniID), - SecondaryPrivateIpAddressCount: aws.Int64(int64(needIPs)), + SecondaryPrivateIpAddressCount: aws.Int32(int32(needIPs)), } } start := time.Now() - output, err := cache.ec2SVC.AssignPrivateIpAddressesWithContext(context.Background(), input) + output, err := cache.ec2SVC.AssignPrivateIpAddresses(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("AssignPrivateIpAddresses").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("AssignPrivateIpAddresses", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { @@ -1726,10 +1745,10 @@ func (cache *EC2InstanceMetadataCache) AllocIPv6Prefixes(eniID string) ([]*strin //We only need to allocate one IPv6 prefix per ENI. input := &ec2.AssignIpv6AddressesInput{ NetworkInterfaceId: aws.String(eniID), - Ipv6PrefixCount: aws.Int64(1), + Ipv6PrefixCount: aws.Int32(1), } start := time.Now() - output, err := cache.ec2SVC.AssignIpv6AddressesWithContext(context.Background(), input) + output, err := cache.ec2SVC.AssignIpv6Addresses(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("AssignIpv6Addresses").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("AssignIpv6AddressesWithContext", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { @@ -1742,7 +1761,7 @@ func (cache *EC2InstanceMetadataCache) AllocIPv6Prefixes(eniID string) ([]*strin if output != nil { log.Debugf("Allocated %d private IPv6 prefix(es)", len(output.AssignedIpv6Prefixes)) } - return output.AssignedIpv6Prefixes, nil + return aws.StringSlice(output.AssignedIpv6Prefixes), nil } // WaitForENIAndIPsAttached waits until the ENI has been attached and the secondary IPs have been added @@ -1822,15 +1841,14 @@ func (cache *EC2InstanceMetadataCache) DeallocIPAddresses(eniID string, ips []st return nil } log.Infof("Trying to unassign the following IPs %v from ENI %s", ips, eniID) - ipsInput := aws.StringSlice(ips) input := &ec2.UnassignPrivateIpAddressesInput{ NetworkInterfaceId: aws.String(eniID), - PrivateIpAddresses: ipsInput, + PrivateIpAddresses: ips, } start := time.Now() - _, err := cache.ec2SVC.UnassignPrivateIpAddressesWithContext(context.Background(), input) + _, err := cache.ec2SVC.UnassignPrivateIpAddresses(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("UnassignPrivateIpAddresses").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("UnassignPrivateIpAddresses", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { @@ -1850,15 +1868,14 @@ func (cache *EC2InstanceMetadataCache) DeallocPrefixAddresses(eniID string, pref return nil } log.Infof("Trying to unassign the following Prefixes %v from ENI %s", prefixes, eniID) - prefixesInput := aws.StringSlice(prefixes) input := &ec2.UnassignPrivateIpAddressesInput{ NetworkInterfaceId: aws.String(eniID), - Ipv4Prefixes: prefixesInput, + Ipv4Prefixes: prefixes, } start := time.Now() - _, err := cache.ec2SVC.UnassignPrivateIpAddressesWithContext(context.Background(), input) + _, err := cache.ec2SVC.UnassignPrivateIpAddresses(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("UnassignPrivateIpAddresses").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("UnassignPrivateIpAddresses", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { @@ -1888,7 +1905,7 @@ func (cache *EC2InstanceMetadataCache) cleanUpLeakedENIsInternal(startupDelay ti } else { // Clean up all the leaked ones we found for _, networkInterface := range networkInterfaces { - eniID := aws.StringValue(networkInterface.NetworkInterfaceId) + eniID := aws.ToString(networkInterface.NetworkInterfaceId) err = cache.deleteENI(eniID, maxENIBackoffDelay) if err != nil { awsUtilsErrInc("cleanUpLeakedENIDeleteErr", err) @@ -1902,25 +1919,25 @@ func (cache *EC2InstanceMetadataCache) cleanUpLeakedENIsInternal(startupDelay ti func (cache *EC2InstanceMetadataCache) tagENIcreateTS(eniID string, maxBackoffDelay time.Duration) { // Tag the ENI with "node.k8s.amazonaws.com/createdAt=currentTime" - tags := []*ec2.Tag{ + tags := []ec2types.Tag{ { Key: aws.String(eniCreatedAtTagKey), Value: aws.String(time.Now().Format(time.RFC3339)), }, } - log.Debugf("Tag untagged ENI %s: key=%s, value=%s", eniID, aws.StringValue(tags[0].Key), aws.StringValue(tags[0].Value)) + log.Debugf("Tag untagged ENI %s: key=%s, value=%s", eniID, aws.ToString(tags[0].Key), aws.ToString(tags[0].Value)) input := &ec2.CreateTagsInput{ - Resources: []*string{ - aws.String(eniID), + Resources: []string{ + eniID, }, Tags: tags, } _ = retry.NWithBackoff(retry.NewSimpleBackoff(500*time.Millisecond, maxBackoffDelay, 0.3, 2), 5, func() error { start := time.Now() - _, err := cache.ec2SVC.CreateTagsWithContext(context.Background(), input) + _, err := cache.ec2SVC.CreateTags(context.Background(), input) prometheusmetrics.Ec2ApiReq.WithLabelValues("CreateTags").Inc() prometheusmetrics.AwsAPILatency.WithLabelValues("CreateTags", fmt.Sprint(err != nil), awsReqStatus(err)).Observe(msSince(start)) if err != nil { @@ -1937,45 +1954,43 @@ func (cache *EC2InstanceMetadataCache) tagENIcreateTS(eniID string, maxBackoffDe // getLeakedENIs calls DescribeNetworkInterfaces to get all available ENIs that were allocated by // the AWS CNI plugin, but were not deleted. -func (cache *EC2InstanceMetadataCache) getLeakedENIs() ([]*ec2.NetworkInterface, error) { - leakedENIFilters := []*ec2.Filter{ +func (cache *EC2InstanceMetadataCache) getLeakedENIs() ([]ec2types.NetworkInterface, error) { + leakedENIFilters := []ec2types.Filter{ { - Name: aws.String("tag-key"), - Values: []*string{ - aws.String(eniNodeTagKey), - }, + Name: aws.String("tag-key"), + Values: []string{eniNodeTagKey}, }, { Name: aws.String("status"), - Values: []*string{ - aws.String(ec2.NetworkInterfaceStatusAvailable), + Values: []string{ + string(ec2types.NetworkInterfaceStatusAvailable), }, }, { Name: aws.String("vpc-id"), - Values: []*string{ - aws.String(cache.vpcID), + Values: []string{ + cache.vpcID, }, }, } if cache.clusterName != "" { - leakedENIFilters = append(leakedENIFilters, &ec2.Filter{ + leakedENIFilters = append(leakedENIFilters, ec2types.Filter{ Name: aws.String(fmt.Sprintf("tag:%s", eniClusterTagKey)), - Values: []*string{ - aws.String(cache.clusterName), + Values: []string{ + cache.clusterName, }, }) } input := &ec2.DescribeNetworkInterfacesInput{ Filters: leakedENIFilters, - MaxResults: aws.Int64(describeENIPageSize), + MaxResults: aws.Int32(describeENIPageSize), } - var networkInterfaces []*ec2.NetworkInterface - filterFn := func(networkInterface *ec2.NetworkInterface) error { + var networkInterfaces []ec2types.NetworkInterface + filterFn := func(networkInterface ec2types.NetworkInterface) error { // Verify the description starts with "aws-K8S-" - if !strings.HasPrefix(aws.StringValue(networkInterface.Description), eniDescriptionPrefix) { + if !strings.HasPrefix(aws.ToString(networkInterface.Description), eniDescriptionPrefix) { return nil } // Check that it's not a newly created ENI @@ -1985,7 +2000,7 @@ func (cache *EC2InstanceMetadataCache) getLeakedENIs() ([]*ec2.NetworkInterface, parsedTime, err := time.Parse(time.RFC3339, value) if err != nil { log.Warnf("ParsedTime format %s is wrong so retagging with current TS", parsedTime) - cache.tagENIcreateTS(aws.StringValue(networkInterface.NetworkInterfaceId), maxENIBackoffDelay) + cache.tagENIcreateTS(aws.ToString(networkInterface.NetworkInterfaceId), maxENIBackoffDelay) } if time.Since(parsedTime) < eniDeleteCooldownTime { log.Infof("Found an ENI created less than 5 minutes ago, so not cleaning it up") @@ -1996,7 +2011,7 @@ func (cache *EC2InstanceMetadataCache) getLeakedENIs() ([]*ec2.NetworkInterface, /* Set a time if we didn't find one. This is to prevent accidentally deleting ENIs that are in the * process of being attached by CNI versions v1.5.x or earlier. */ - cache.tagENIcreateTS(aws.StringValue(networkInterface.NetworkInterfaceId), maxENIBackoffDelay) + cache.tagENIcreateTS(aws.ToString(networkInterface.NetworkInterfaceId), maxENIBackoffDelay) return nil } networkInterfaces = append(networkInterfaces, networkInterface) @@ -2087,31 +2102,24 @@ func (cache *EC2InstanceMetadataCache) IsUnmanagedENI(eniID string) bool { return false } -func (cache *EC2InstanceMetadataCache) getENIsFromPaginatedDescribeNetworkInterfaces( - input *ec2.DescribeNetworkInterfacesInput, filterFn func(networkInterface *ec2.NetworkInterface) error) error { - pageNum := 0 - var innerErr error - pageFn := func(output *ec2.DescribeNetworkInterfacesOutput, lastPage bool) (nextPage bool) { - pageNum++ - log.Debugf("EC2 DescribeNetworkInterfaces succeeded with %d results on page %d", - len(output.NetworkInterfaces), pageNum) - for _, eni := range output.NetworkInterfaces { +func (cache *EC2InstanceMetadataCache) getENIsFromPaginatedDescribeNetworkInterfaces(input *ec2.DescribeNetworkInterfacesInput, filterFn func(networkInterface ec2types.NetworkInterface) error) error { + paginator := ec2.NewDescribeNetworkInterfacesPaginator(cache.ec2SVC, input) + for paginator.HasMorePages() { + page, err := paginator.NextPage(context.TODO()) + if err != nil { + checkAPIErrorAndBroadcastEvent(err, "ec2:DescribeNetworkInterfaces") + awsAPIErrInc("DescribeNetworkInterfaces", err) + prometheusmetrics.Ec2ApiErr.WithLabelValues("DescribeNetworkInterfaces").Inc() + return err + } + for _, eni := range page.NetworkInterfaces { if err := filterFn(eni); err != nil { - innerErr = err - return false + return err } } - return true - } - - if err := cache.ec2SVC.DescribeNetworkInterfacesPagesWithContext(context.TODO(), input, pageFn); err != nil { - checkAPIErrorAndBroadcastEvent(err, "ec2:DescribeNetworkInterfaces") - awsAPIErrInc("DescribeNetworkInterfaces", err) - prometheusmetrics.Ec2ApiErr.WithLabelValues("DescribeNetworkInterfaces").Inc() - return err } prometheusmetrics.Ec2ApiReq.WithLabelValues("DescribeNetworkInterfaces").Inc() - return innerErr + return nil } // SetMultiCardENIs creates a StringSet tracking ENIs not behind the default network card index @@ -2139,8 +2147,9 @@ func (cache *EC2InstanceMetadataCache) IsPrimaryENI(eniID string) bool { } func checkAPIErrorAndBroadcastEvent(err error, api string) { - if aerr, ok := err.(awserr.Error); ok { - if aerr.Code() == "UnauthorizedOperation" { + log.Debugf("checkAPIErrorAndBroadcastEvent resulted in %v", err) + if errors.As(err, &awsAPIError) { + if awsAPIError.ErrorCode() == "UnauthorizedOperation" { if eventRecorder := eventrecorder.Get(); eventRecorder != nil { eventRecorder.SendPodEvent(v1.EventTypeWarning, "MissingIAMPermissions", api, fmt.Sprintf("Unauthorized operation: failed to call %v due to missing permissions. Please refer https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/iam-policy.md to attach relevant policy to IAM role", api)) diff --git a/pkg/awsutils/awsutils_test.go b/pkg/awsutils/awsutils_test.go index 897c451d0b..cd268b3c82 100644 --- a/pkg/awsutils/awsutils_test.go +++ b/pkg/awsutils/awsutils_test.go @@ -23,19 +23,20 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/ec2" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" + + "github.com/aws/smithy-go" + + "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/golang/mock/gomock" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/assert" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - mock_ec2wrapper "github.com/aws/amazon-vpc-cni-k8s/pkg/ec2wrapper/mocks" "github.com/aws/amazon-vpc-cni-k8s/pkg/utils/eventrecorder" "github.com/aws/amazon-vpc-cni-k8s/utils/prometheusmetrics" + "github.com/aws/aws-sdk-go-v2/aws" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -143,8 +144,7 @@ func testMetadataWithPrefixes(overrides map[string]interface{}) FakeIMDS { return FakeIMDS(data) } -func setup(t *testing.T) (*gomock.Controller, - *mock_ec2wrapper.MockEC2) { +func setup(t *testing.T) (*gomock.Controller, *mock_ec2wrapper.MockEC2) { ctrl := gomock.NewController(t) setupEventRecorder(t) return ctrl, @@ -284,7 +284,7 @@ func TestAWSGetFreeDeviceNumberOnErr(t *testing.T) { defer ctrl.Finish() // test error handling - mockEC2.EXPECT().DescribeInstancesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("error on DescribeInstancesWithContext")) + mockEC2.EXPECT().DescribeInstances(gomock.Any(), gomock.Any()).Return(nil, errors.New("error on DescribeInstances")) cache := &EC2InstanceMetadataCache{ec2SVC: mockEC2} _, err := cache.awsGetFreeDeviceNumber() @@ -296,18 +296,20 @@ func TestAWSGetFreeDeviceNumberNoDevice(t *testing.T) { defer ctrl.Finish() // test no free index - ec2ENIs := make([]*ec2.InstanceNetworkInterface, 0) + ec2ENIs := make([]ec2types.InstanceNetworkInterface, 0) for i := 0; i < maxENIs; i++ { - var deviceNums [maxENIs]int64 - deviceNums[i] = int64(i) - ec2ENI := &ec2.InstanceNetworkInterface{Attachment: &ec2.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNums[i], NetworkCardIndex: aws.Int64(0)}} + deviceNum := int32(i) + ec2ENI := ec2types.InstanceNetworkInterface{Attachment: &ec2types.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum, NetworkCardIndex: aws.Int32(0)}} ec2ENIs = append(ec2ENIs, ec2ENI) } - result := &ec2.DescribeInstancesOutput{ - Reservations: []*ec2.Reservation{{Instances: []*ec2.Instance{{NetworkInterfaces: ec2ENIs}}}}} - mockEC2.EXPECT().DescribeInstancesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) + result := &ec2.DescribeInstancesOutput{Reservations: []ec2types.Reservation{{ + Instances: []ec2types.Instance{{ + NetworkInterfaces: ec2ENIs, + }}}}} + + mockEC2.EXPECT().DescribeInstances(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) cache := &EC2InstanceMetadataCache{ec2SVC: mockEC2} _, err := cache.awsGetFreeDeviceNumber() @@ -322,15 +324,15 @@ func TestGetENIAttachmentID(t *testing.T) { testCases := []struct { name string output *ec2.DescribeNetworkInterfacesOutput - awsErr error + err error expID *string expErr error }{ { "success with attachment", &ec2.DescribeNetworkInterfacesOutput{ - NetworkInterfaces: []*ec2.NetworkInterface{{ - Attachment: &ec2.NetworkInterfaceAttachment{ + NetworkInterfaces: []ec2types.NetworkInterface{{ + Attachment: &ec2types.NetworkInterfaceAttachment{ AttachmentId: attachmentID, }, }}, @@ -342,7 +344,7 @@ func TestGetENIAttachmentID(t *testing.T) { { "success no Attachment", &ec2.DescribeNetworkInterfacesOutput{ - NetworkInterfaces: []*ec2.NetworkInterface{{}}, + NetworkInterfaces: []ec2types.NetworkInterface{{}}, }, nil, nil, @@ -351,7 +353,7 @@ func TestGetENIAttachmentID(t *testing.T) { { "error empty net ifaces", &ec2.DescribeNetworkInterfacesOutput{ - NetworkInterfaces: []*ec2.NetworkInterface{}, + NetworkInterfaces: []ec2types.NetworkInterface{}, }, nil, nil, @@ -360,14 +362,21 @@ func TestGetENIAttachmentID(t *testing.T) { { "not found error", nil, - awserr.New("InvalidNetworkInterfaceID.NotFound", "", nil), + &smithy.GenericAPIError{Code: "InvalidNetworkInterfaceID.NotFound", Message: "not found", Fault: 0}, + nil, + ErrENINotFound, + }, + { + "not found error", + nil, + &smithy.GenericAPIError{Code: "InvalidNetworkInterfaceID.NotFound", Message: "", Fault: 0}, nil, ErrENINotFound, }, } for _, tc := range testCases { - mockEC2.EXPECT().DescribeNetworkInterfacesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(tc.output, tc.awsErr) + mockEC2.EXPECT().DescribeNetworkInterfaces(gomock.Any(), gomock.Any(), gomock.Any()).Return(tc.output, tc.err) cache := &EC2InstanceMetadataCache{ec2SVC: mockEC2} id, err := cache.getENIAttachmentID("test-eni") @@ -381,38 +390,46 @@ func TestDescribeAllENIs(t *testing.T) { defer ctrl.Finish() result := &ec2.DescribeNetworkInterfacesOutput{ - NetworkInterfaces: []*ec2.NetworkInterface{{ - TagSet: []*ec2.Tag{ + NetworkInterfaces: []ec2types.NetworkInterface{{ + TagSet: []ec2types.Tag{ {Key: aws.String("foo"), Value: aws.String("foo-value")}, }, - Attachment: &ec2.NetworkInterfaceAttachment{ - NetworkCardIndex: aws.Int64(0), + Attachment: &ec2types.NetworkInterfaceAttachment{ + NetworkCardIndex: aws.Int32(0), }, NetworkInterfaceId: aws.String(primaryeniID), }}, } - expectedError := awserr.New("InvalidNetworkInterfaceID.NotFound", "no 'eni-xxx'", nil) - noMessageError := awserr.New("InvalidNetworkInterfaceID.NotFound", "no message", nil) + expectedError := &smithy.GenericAPIError{ + Code: "InvalidNetworkInterfaceID.NotFound", + Message: "no 'eni-xxx'", + } + + noMessageError := &smithy.GenericAPIError{ + Code: "InvalidNetworkInterfaceID.NotFound", + Message: "no message", + } + err := errors.New("other Error") testCases := []struct { name string exptags map[string]TagMap n int - awsErr error + err error expErr error }{ {"Success DescribeENI", map[string]TagMap{"eni-00000000": {"foo": "foo-value"}}, 1, nil, nil}, - {"Not found error", nil, maxENIEC2APIRetries, awserr.New("InvalidNetworkInterfaceID.NotFound", "no 'eni-xxx'", nil), expectedError}, - {"Not found, no message", nil, maxENIEC2APIRetries, awserr.New("InvalidNetworkInterfaceID.NotFound", "no message", nil), noMessageError}, + {"Not found error", nil, maxENIEC2APIRetries, &smithy.GenericAPIError{Code: "InvalidNetworkInterfaceID.NotFound", Message: "no 'eni-xxx'"}, expectedError}, + {"Not found, no message", nil, maxENIEC2APIRetries, &smithy.GenericAPIError{Code: "InvalidNetworkInterfaceID.NotFound", Message: "no message"}, noMessageError}, {"Other error", nil, maxENIEC2APIRetries, err, err}, } mockMetadata := testMetadata(nil) for _, tc := range testCases { - mockEC2.EXPECT().DescribeNetworkInterfacesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Times(tc.n).Return(result, tc.awsErr) + mockEC2.EXPECT().DescribeNetworkInterfaces(gomock.Any(), gomock.Any(), gomock.Any()).Times(tc.n).Return(result, tc.err) cache := &EC2InstanceMetadataCache{imds: TypedIMDS{mockMetadata}, ec2SVC: mockEC2} metaData, err := cache.DescribeAllENIs() assert.Equal(t, tc.expErr, err, tc.name) @@ -426,12 +443,12 @@ func TestAllocENI(t *testing.T) { mockMetadata := testMetadata(nil) - ipAddressCount := int64(100) + ipAddressCount := int32(100) subnetResult := &ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{{ - AvailableIpAddressCount: aws.Int64(ipAddressCount), + Subnets: []ec2types.Subnet{{ + AvailableIpAddressCount: &ipAddressCount, SubnetId: aws.String(subnetID), - Tags: []*ec2.Tag{ + Tags: []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cni"), Value: aws.String("1"), @@ -439,31 +456,31 @@ func TestAllocENI(t *testing.T) { }, }}, } - mockEC2.EXPECT().DescribeSubnetsWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) + mockEC2.EXPECT().DescribeSubnets(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) cureniID := eniID - eni := ec2.CreateNetworkInterfaceOutput{NetworkInterface: &ec2.NetworkInterface{NetworkInterfaceId: &cureniID}} - mockEC2.EXPECT().CreateNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(&eni, nil) + eni := ec2.CreateNetworkInterfaceOutput{NetworkInterface: &ec2types.NetworkInterface{NetworkInterfaceId: &cureniID}} + mockEC2.EXPECT().CreateNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(&eni, nil) // 2 ENIs, uses device number 0 3, expect to find free at 1 - ec2ENIs := make([]*ec2.InstanceNetworkInterface, 0) - deviceNum1 := int64(0) - ec2ENI := &ec2.InstanceNetworkInterface{Attachment: &ec2.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum1}} + ec2ENIs := make([]ec2types.InstanceNetworkInterface, 0) + deviceNum1 := int32(0) + ec2ENI := ec2types.InstanceNetworkInterface{Attachment: &ec2types.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum1}} ec2ENIs = append(ec2ENIs, ec2ENI) - deviceNum2 := int64(3) - ec2ENI = &ec2.InstanceNetworkInterface{Attachment: &ec2.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum2}} + deviceNum2 := int32(3) + ec2ENI = ec2types.InstanceNetworkInterface{Attachment: &ec2types.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum2}} ec2ENIs = append(ec2ENIs, ec2ENI) result := &ec2.DescribeInstancesOutput{ - Reservations: []*ec2.Reservation{{Instances: []*ec2.Instance{{NetworkInterfaces: ec2ENIs}}}}} + Reservations: []ec2types.Reservation{{Instances: []ec2types.Instance{{NetworkInterfaces: ec2ENIs}}}}} - mockEC2.EXPECT().DescribeInstancesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) + mockEC2.EXPECT().DescribeInstances(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) attachmentID := "eni-attach-58ddda9d" attachResult := &ec2.AttachNetworkInterfaceOutput{ AttachmentId: &attachmentID} - mockEC2.EXPECT().AttachNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(attachResult, nil) - mockEC2.EXPECT().ModifyNetworkInterfaceAttributeWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + mockEC2.EXPECT().AttachNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(attachResult, nil) + mockEC2.EXPECT().ModifyNetworkInterfaceAttribute(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) cache := &EC2InstanceMetadataCache{ ec2SVC: mockEC2, @@ -482,12 +499,12 @@ func TestAllocENINoFreeDevice(t *testing.T) { mockMetadata := testMetadata(nil) - ipAddressCount := int64(100) + ipAddressCount := int32(100) subnetResult := &ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{{ + Subnets: []ec2types.Subnet{{ AvailableIpAddressCount: &ipAddressCount, SubnetId: aws.String(subnetID), - Tags: []*ec2.Tag{ + Tags: []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cni"), Value: aws.String("1"), @@ -495,26 +512,25 @@ func TestAllocENINoFreeDevice(t *testing.T) { }, }}, } - mockEC2.EXPECT().DescribeSubnetsWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) + mockEC2.EXPECT().DescribeSubnets(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) cureniID := eniID - eni := ec2.CreateNetworkInterfaceOutput{NetworkInterface: &ec2.NetworkInterface{NetworkInterfaceId: &cureniID}} - mockEC2.EXPECT().CreateNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(&eni, nil) + eni := ec2.CreateNetworkInterfaceOutput{NetworkInterface: &ec2types.NetworkInterface{NetworkInterfaceId: &cureniID}} + mockEC2.EXPECT().CreateNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(&eni, nil) // test no free index - ec2ENIs := make([]*ec2.InstanceNetworkInterface, 0) + ec2ENIs := make([]ec2types.InstanceNetworkInterface, 0) for i := 0; i < maxENIs; i++ { - var deviceNums [maxENIs]int64 - deviceNums[i] = int64(i) - ec2ENI := &ec2.InstanceNetworkInterface{Attachment: &ec2.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNums[i], NetworkCardIndex: aws.Int64(0)}} + deviceNum := int32(i) + ec2ENI := ec2types.InstanceNetworkInterface{Attachment: &ec2types.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum, NetworkCardIndex: aws.Int32(0)}} ec2ENIs = append(ec2ENIs, ec2ENI) } result := &ec2.DescribeInstancesOutput{ - Reservations: []*ec2.Reservation{{Instances: []*ec2.Instance{{NetworkInterfaces: ec2ENIs}}}}} + Reservations: []ec2types.Reservation{{Instances: []ec2types.Instance{{NetworkInterfaces: ec2ENIs}}}}} - mockEC2.EXPECT().DescribeInstancesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) - mockEC2.EXPECT().DeleteNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + mockEC2.EXPECT().DescribeInstances(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) + mockEC2.EXPECT().DeleteNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) cache := &EC2InstanceMetadataCache{ ec2SVC: mockEC2, @@ -533,12 +549,12 @@ func TestAllocENIMaxReached(t *testing.T) { mockMetadata := testMetadata(nil) - ipAddressCount := int64(100) + ipAddressCount := int32(100) subnetResult := &ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{{ + Subnets: []ec2types.Subnet{{ AvailableIpAddressCount: &ipAddressCount, SubnetId: aws.String(subnetID), - Tags: []*ec2.Tag{ + Tags: []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cni"), Value: aws.String("1"), @@ -546,28 +562,28 @@ func TestAllocENIMaxReached(t *testing.T) { }, }}, } - mockEC2.EXPECT().DescribeSubnetsWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) + mockEC2.EXPECT().DescribeSubnets(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) cureniID := eniID - eni := ec2.CreateNetworkInterfaceOutput{NetworkInterface: &ec2.NetworkInterface{NetworkInterfaceId: &cureniID}} - mockEC2.EXPECT().CreateNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(&eni, nil) + eni := ec2.CreateNetworkInterfaceOutput{NetworkInterface: &ec2types.NetworkInterface{NetworkInterfaceId: &cureniID}} + mockEC2.EXPECT().CreateNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(&eni, nil) // 2 ENIs, uses device number 0 3, expect to find free at 1 - ec2ENIs := make([]*ec2.InstanceNetworkInterface, 0) - deviceNum1 := int64(0) - ec2ENI := &ec2.InstanceNetworkInterface{Attachment: &ec2.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum1}} + ec2ENIs := make([]ec2types.InstanceNetworkInterface, 0) + deviceNum1 := int32(0) + ec2ENI := ec2types.InstanceNetworkInterface{Attachment: &ec2types.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum1}} ec2ENIs = append(ec2ENIs, ec2ENI) - deviceNum2 := int64(3) - ec2ENI = &ec2.InstanceNetworkInterface{Attachment: &ec2.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum2}} + deviceNum2 := int32(3) + ec2ENI = ec2types.InstanceNetworkInterface{Attachment: &ec2types.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum2}} ec2ENIs = append(ec2ENIs, ec2ENI) result := &ec2.DescribeInstancesOutput{ - Reservations: []*ec2.Reservation{{Instances: []*ec2.Instance{{NetworkInterfaces: ec2ENIs}}}}} + Reservations: []ec2types.Reservation{{Instances: []ec2types.Instance{{NetworkInterfaces: ec2ENIs}}}}} - mockEC2.EXPECT().DescribeInstancesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) - mockEC2.EXPECT().AttachNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("AttachmentLimitExceeded")) - mockEC2.EXPECT().DeleteNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + mockEC2.EXPECT().DescribeInstances(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) + mockEC2.EXPECT().AttachNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("AttachmentLimitExceeded")) + mockEC2.EXPECT().DeleteNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) cache := &EC2InstanceMetadataCache{ ec2SVC: mockEC2, @@ -584,12 +600,12 @@ func TestAllocENIWithIPAddresses(t *testing.T) { ctrl, mockEC2 := setup(t) defer ctrl.Finish() - ipAddressCount := int64(100) + ipAddressCount := int32(100) subnetResult := &ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{{ + Subnets: []ec2types.Subnet{{ AvailableIpAddressCount: &ipAddressCount, SubnetId: aws.String(subnetID), - Tags: []*ec2.Tag{ + Tags: []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cni"), Value: aws.String("1"), @@ -597,41 +613,41 @@ func TestAllocENIWithIPAddresses(t *testing.T) { }, }}, } - mockEC2.EXPECT().DescribeSubnetsWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) + mockEC2.EXPECT().DescribeSubnets(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) // when required IP numbers(5) is below ENI's limit(30) currentEniID := eniID - eni := ec2.CreateNetworkInterfaceOutput{NetworkInterface: &ec2.NetworkInterface{NetworkInterfaceId: ¤tEniID}} - mockEC2.EXPECT().CreateNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(&eni, nil) + eni := ec2.CreateNetworkInterfaceOutput{NetworkInterface: &ec2types.NetworkInterface{NetworkInterfaceId: ¤tEniID}} + mockEC2.EXPECT().CreateNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(&eni, nil) - ec2ENIs := make([]*ec2.InstanceNetworkInterface, 0) - deviceNum1 := int64(0) - ec2ENI := &ec2.InstanceNetworkInterface{Attachment: &ec2.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum1}} + ec2ENIs := make([]ec2types.InstanceNetworkInterface, 0) + deviceNum1 := int32(0) + ec2ENI := ec2types.InstanceNetworkInterface{Attachment: &ec2types.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum1}} ec2ENIs = append(ec2ENIs, ec2ENI) - deviceNum2 := int64(3) - ec2ENI = &ec2.InstanceNetworkInterface{Attachment: &ec2.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum2}} + deviceNum2 := int32(3) + ec2ENI = ec2types.InstanceNetworkInterface{Attachment: &ec2types.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum2}} ec2ENIs = append(ec2ENIs, ec2ENI) result := &ec2.DescribeInstancesOutput{ - Reservations: []*ec2.Reservation{{Instances: []*ec2.Instance{{NetworkInterfaces: ec2ENIs}}}}} - mockEC2.EXPECT().DescribeInstancesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) + Reservations: []ec2types.Reservation{{Instances: []ec2types.Instance{{NetworkInterfaces: ec2ENIs}}}}} + mockEC2.EXPECT().DescribeInstances(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) attachmentID := "eni-attach-58ddda9d" attachResult := &ec2.AttachNetworkInterfaceOutput{ AttachmentId: &attachmentID} - mockEC2.EXPECT().AttachNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(attachResult, nil) - mockEC2.EXPECT().ModifyNetworkInterfaceAttributeWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + mockEC2.EXPECT().AttachNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(attachResult, nil) + mockEC2.EXPECT().ModifyNetworkInterfaceAttribute(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) cache := &EC2InstanceMetadataCache{ec2SVC: mockEC2, instanceType: "c5n.18xlarge", useSubnetDiscovery: true} _, err := cache.AllocENI(false, nil, subnetID, 5) assert.NoError(t, err) // when required IP numbers(50) is higher than ENI's limit(49) - mockEC2.EXPECT().DescribeSubnetsWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) - mockEC2.EXPECT().CreateNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(&eni, nil) - mockEC2.EXPECT().DescribeInstancesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) - mockEC2.EXPECT().AttachNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(attachResult, nil) - mockEC2.EXPECT().ModifyNetworkInterfaceAttributeWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + mockEC2.EXPECT().DescribeSubnets(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) + mockEC2.EXPECT().CreateNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(&eni, nil) + mockEC2.EXPECT().DescribeInstances(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) + mockEC2.EXPECT().AttachNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(attachResult, nil) + mockEC2.EXPECT().ModifyNetworkInterfaceAttribute(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) cache = &EC2InstanceMetadataCache{ec2SVC: mockEC2, instanceType: "c5n.18xlarge", useSubnetDiscovery: true} _, err = cache.AllocENI(false, nil, subnetID, 49) assert.NoError(t, err) @@ -643,12 +659,12 @@ func TestAllocENIWithIPAddressesAlreadyFull(t *testing.T) { mockMetadata := testMetadata(nil) - ipAddressCount := int64(100) + ipAddressCount := int32(100) subnetResult := &ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{{ + Subnets: []ec2types.Subnet{{ AvailableIpAddressCount: &ipAddressCount, SubnetId: aws.String(subnetID), - Tags: []*ec2.Tag{ + Tags: []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cni"), Value: aws.String("1"), @@ -656,10 +672,10 @@ func TestAllocENIWithIPAddressesAlreadyFull(t *testing.T) { }, }}, } - mockEC2.EXPECT().DescribeSubnetsWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) + mockEC2.EXPECT().DescribeSubnets(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) - retErr := awserr.New("PrivateIpAddressLimitExceeded", "Too many IPs already allocated", nil) - mockEC2.EXPECT().CreateNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, retErr) + retErr := &smithy.GenericAPIError{Code: "PrivateIpAddressLimitExceeded", Message: "Too many IPs already allocated"} + mockEC2.EXPECT().CreateNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, retErr) cache := &EC2InstanceMetadataCache{ ec2SVC: mockEC2, @@ -677,12 +693,12 @@ func TestAllocENIWithPrefixAddresses(t *testing.T) { mockMetadata := testMetadata(nil) - ipAddressCount := int64(100) + ipAddressCount := int32(100) subnetResult := &ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{{ + Subnets: []ec2types.Subnet{{ AvailableIpAddressCount: &ipAddressCount, SubnetId: aws.String(subnetID), - Tags: []*ec2.Tag{ + Tags: []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cni"), Value: aws.String("1"), @@ -690,29 +706,29 @@ func TestAllocENIWithPrefixAddresses(t *testing.T) { }, }}, } - mockEC2.EXPECT().DescribeSubnetsWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) + mockEC2.EXPECT().DescribeSubnets(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) currentEniID := eniID - eni := ec2.CreateNetworkInterfaceOutput{NetworkInterface: &ec2.NetworkInterface{NetworkInterfaceId: ¤tEniID}} - mockEC2.EXPECT().CreateNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(&eni, nil) + eni := ec2.CreateNetworkInterfaceOutput{NetworkInterface: &ec2types.NetworkInterface{NetworkInterfaceId: ¤tEniID}} + mockEC2.EXPECT().CreateNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(&eni, nil) - ec2ENIs := make([]*ec2.InstanceNetworkInterface, 0) - deviceNum1 := int64(0) - ec2ENI := &ec2.InstanceNetworkInterface{Attachment: &ec2.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum1}} + ec2ENIs := make([]ec2types.InstanceNetworkInterface, 0) + deviceNum1 := int32(0) + ec2ENI := ec2types.InstanceNetworkInterface{Attachment: &ec2types.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum1}} ec2ENIs = append(ec2ENIs, ec2ENI) - deviceNum2 := int64(3) - ec2ENI = &ec2.InstanceNetworkInterface{Attachment: &ec2.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum2}} + deviceNum2 := int32(3) + ec2ENI = ec2types.InstanceNetworkInterface{Attachment: &ec2types.InstanceNetworkInterfaceAttachment{DeviceIndex: &deviceNum2}} ec2ENIs = append(ec2ENIs, ec2ENI) result := &ec2.DescribeInstancesOutput{ - Reservations: []*ec2.Reservation{{Instances: []*ec2.Instance{{NetworkInterfaces: ec2ENIs}}}}} - mockEC2.EXPECT().DescribeInstancesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) + Reservations: []ec2types.Reservation{{Instances: []ec2types.Instance{{NetworkInterfaces: ec2ENIs}}}}} + mockEC2.EXPECT().DescribeInstances(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) attachmentID := "eni-attach-58ddda9d" attachResult := &ec2.AttachNetworkInterfaceOutput{ AttachmentId: &attachmentID} - mockEC2.EXPECT().AttachNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(attachResult, nil) - mockEC2.EXPECT().ModifyNetworkInterfaceAttributeWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + mockEC2.EXPECT().AttachNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(attachResult, nil) + mockEC2.EXPECT().ModifyNetworkInterfaceAttribute(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) cache := &EC2InstanceMetadataCache{ ec2SVC: mockEC2, @@ -731,12 +747,12 @@ func TestAllocENIWithPrefixesAlreadyFull(t *testing.T) { mockMetadata := testMetadata(nil) - ipAddressCount := int64(100) + ipAddressCount := int32(100) subnetResult := &ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{{ + Subnets: []ec2types.Subnet{{ AvailableIpAddressCount: &ipAddressCount, SubnetId: aws.String(subnetID), - Tags: []*ec2.Tag{ + Tags: []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cni"), Value: aws.String("1"), @@ -744,10 +760,10 @@ func TestAllocENIWithPrefixesAlreadyFull(t *testing.T) { }, }}, } - mockEC2.EXPECT().DescribeSubnetsWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) + mockEC2.EXPECT().DescribeSubnets(gomock.Any(), gomock.Any(), gomock.Any()).Return(subnetResult, nil) - retErr := awserr.New("PrivateIpAddressLimitExceeded", "Too many IPs already allocated", nil) - mockEC2.EXPECT().CreateNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, retErr) + retErr := &smithy.GenericAPIError{Code: "PrivateIpAddressLimitExceeded", Message: "Too many IPs already allocated"} + mockEC2.EXPECT().CreateNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, retErr) cache := &EC2InstanceMetadataCache{ ec2SVC: mockEC2, @@ -765,12 +781,12 @@ func TestFreeENI(t *testing.T) { defer ctrl.Finish() attachmentID := eniAttachID - attachment := &ec2.NetworkInterfaceAttachment{AttachmentId: &attachmentID} + attachment := &ec2types.NetworkInterfaceAttachment{AttachmentId: &attachmentID} result := &ec2.DescribeNetworkInterfacesOutput{ - NetworkInterfaces: []*ec2.NetworkInterface{{Attachment: attachment}}} - mockEC2.EXPECT().DescribeNetworkInterfacesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) - mockEC2.EXPECT().DetachNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) - mockEC2.EXPECT().DeleteNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + NetworkInterfaces: []ec2types.NetworkInterface{{Attachment: attachment}}} + mockEC2.EXPECT().DescribeNetworkInterfaces(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) + mockEC2.EXPECT().DetachNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + mockEC2.EXPECT().DeleteNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) cache := &EC2InstanceMetadataCache{ ec2SVC: mockEC2, @@ -785,15 +801,15 @@ func TestFreeENIRetry(t *testing.T) { defer ctrl.Finish() attachmentID := eniAttachID - attachment := &ec2.NetworkInterfaceAttachment{AttachmentId: &attachmentID} + attachment := &ec2types.NetworkInterfaceAttachment{AttachmentId: &attachmentID} result := &ec2.DescribeNetworkInterfacesOutput{ - NetworkInterfaces: []*ec2.NetworkInterface{{Attachment: attachment}}} - mockEC2.EXPECT().DescribeNetworkInterfacesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) + NetworkInterfaces: []ec2types.NetworkInterface{{Attachment: attachment}}} + mockEC2.EXPECT().DescribeNetworkInterfaces(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) // retry 2 times - mockEC2.EXPECT().DetachNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) - mockEC2.EXPECT().DeleteNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("testing retrying delete")) - mockEC2.EXPECT().DeleteNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + mockEC2.EXPECT().DetachNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + mockEC2.EXPECT().DeleteNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("testing retrying delete")) + mockEC2.EXPECT().DeleteNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) cache := &EC2InstanceMetadataCache{ ec2SVC: mockEC2, @@ -808,7 +824,11 @@ func TestAwsAPIErrInc(t *testing.T) { prometheusmetrics.AwsAPIErr.Reset() // Test case 1: AWS error - awsErr := awserr.New("InvalidParameterException", "The parameter is invalid", nil) + awsErr := &smithy.GenericAPIError{ + Code: "InvalidParameterException", + Message: "The parameter is invalid", + Fault: smithy.FaultUnknown, + } awsAPIErrInc("CreateNetworkInterface", awsErr) // Verify metric was incremented with correct labels @@ -835,14 +855,14 @@ func TestFreeENIRetryMax(t *testing.T) { defer ctrl.Finish() attachmentID := eniAttachID - attachment := &ec2.NetworkInterfaceAttachment{AttachmentId: &attachmentID} + attachment := &ec2types.NetworkInterfaceAttachment{AttachmentId: &attachmentID} result := &ec2.DescribeNetworkInterfacesOutput{ - NetworkInterfaces: []*ec2.NetworkInterface{{Attachment: attachment}}} - mockEC2.EXPECT().DescribeNetworkInterfacesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) - mockEC2.EXPECT().DetachNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + NetworkInterfaces: []ec2types.NetworkInterface{{Attachment: attachment}}} + mockEC2.EXPECT().DescribeNetworkInterfaces(gomock.Any(), gomock.Any(), gomock.Any()).Return(result, nil) + mockEC2.EXPECT().DetachNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) for i := 0; i < maxENIEC2APIRetries; i++ { - mockEC2.EXPECT().DeleteNetworkInterfaceWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("testing retrying delete")) + mockEC2.EXPECT().DeleteNetworkInterface(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("testing retrying delete")) } cache := &EC2InstanceMetadataCache{ @@ -857,7 +877,7 @@ func TestFreeENIDescribeErr(t *testing.T) { ctrl, mockEC2 := setup(t) defer ctrl.Finish() - mockEC2.EXPECT().DescribeNetworkInterfacesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("Error on DescribeNetworkInterfacesWithContext")) + mockEC2.EXPECT().DescribeNetworkInterfaces(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("Error on DescribeNetworkInterfacesWithContext")) cache := &EC2InstanceMetadataCache{ ec2SVC: mockEC2, @@ -870,11 +890,11 @@ func TestFreeENIDescribeErr(t *testing.T) { func TestDescribeInstanceTypes(t *testing.T) { ctrl, mockEC2 := setup(t) defer ctrl.Finish() - mockEC2.EXPECT().DescribeInstanceTypesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(&ec2.DescribeInstanceTypesOutput{ - InstanceTypes: []*ec2.InstanceTypeInfo{ - {InstanceType: aws.String("not-there"), NetworkInfo: &ec2.NetworkInfo{ - MaximumNetworkInterfaces: aws.Int64(9), - Ipv4AddressesPerInterface: aws.Int64(99)}, + mockEC2.EXPECT().DescribeInstanceTypes(gomock.Any(), gomock.Any(), gomock.Any()).Return(&ec2.DescribeInstanceTypesOutput{ + InstanceTypes: []ec2types.InstanceTypeInfo{ + {InstanceType: "not-there", NetworkInfo: &ec2types.NetworkInfo{ + MaximumNetworkInterfaces: aws.Int32(9), + Ipv4AddressesPerInterface: aws.Int32(99)}, }, }, NextToken: nil, @@ -894,7 +914,7 @@ func TestAllocIPAddress(t *testing.T) { ctrl, mockEC2 := setup(t) defer ctrl.Finish() - mockEC2.EXPECT().AssignPrivateIpAddressesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(&ec2.AssignPrivateIpAddressesOutput{}, nil) + mockEC2.EXPECT().AssignPrivateIpAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Return(&ec2.AssignPrivateIpAddressesOutput{}, nil) cache := &EC2InstanceMetadataCache{ec2SVC: mockEC2} err := cache.AllocIPAddress("eni-id") @@ -905,7 +925,7 @@ func TestAllocIPAddressOnErr(t *testing.T) { ctrl, mockEC2 := setup(t) defer ctrl.Finish() - mockEC2.EXPECT().AssignPrivateIpAddressesWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("Error on AssignPrivateIpAddressesWithContext")) + mockEC2.EXPECT().AssignPrivateIpAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("Error on AssignPrivateIpAddressesWithContext")) cache := &EC2InstanceMetadataCache{ec2SVC: mockEC2} err := cache.AllocIPAddress("eni-id") @@ -919,9 +939,9 @@ func TestAllocIPAddresses(t *testing.T) { // when required IP numbers(5) is below ENI's limit(30) input := &ec2.AssignPrivateIpAddressesInput{ NetworkInterfaceId: aws.String(eniID), - SecondaryPrivateIpAddressCount: aws.Int64(5), + SecondaryPrivateIpAddressCount: aws.Int32(5), } - mockEC2.EXPECT().AssignPrivateIpAddressesWithContext(gomock.Any(), input, gomock.Any()).Return(nil, nil) + mockEC2.EXPECT().AssignPrivateIpAddresses(gomock.Any(), input, gomock.Any()).Return(nil, nil) cache := &EC2InstanceMetadataCache{ec2SVC: mockEC2, instanceType: "c5n.18xlarge"} _, err := cache.AllocIPAddresses(eniID, 5) @@ -930,14 +950,14 @@ func TestAllocIPAddresses(t *testing.T) { // when required IP numbers(50) is higher than ENI's limit(49) input = &ec2.AssignPrivateIpAddressesInput{ NetworkInterfaceId: aws.String(eniID), - SecondaryPrivateIpAddressCount: aws.Int64(49), + SecondaryPrivateIpAddressCount: aws.Int32(49), } - addresses := make([]*ec2.AssignedPrivateIpAddress, 49) + addresses := make([]ec2types.AssignedPrivateIpAddress, 49) output := ec2.AssignPrivateIpAddressesOutput{ AssignedPrivateIpAddresses: addresses, NetworkInterfaceId: aws.String(eniID), } - mockEC2.EXPECT().AssignPrivateIpAddressesWithContext(gomock.Any(), input, gomock.Any()).Return(&output, nil) + mockEC2.EXPECT().AssignPrivateIpAddresses(gomock.Any(), input, gomock.Any()).Return(&output, nil) cache = &EC2InstanceMetadataCache{ec2SVC: mockEC2, instanceType: "c5n.18xlarge"} _, err = cache.AllocIPAddresses(eniID, 50) @@ -954,12 +974,12 @@ func TestAllocIPAddressesAlreadyFull(t *testing.T) { // The required IP numbers(14) is the ENI's limit(14) input := &ec2.AssignPrivateIpAddressesInput{ NetworkInterfaceId: aws.String(eniID), - SecondaryPrivateIpAddressCount: aws.Int64(14), + SecondaryPrivateIpAddressCount: aws.Int32(14), } cache := &EC2InstanceMetadataCache{ec2SVC: mockEC2, instanceType: "t3.xlarge"} - retErr := awserr.New("PrivateIpAddressLimitExceeded", "Too many IPs already allocated", nil) - mockEC2.EXPECT().AssignPrivateIpAddressesWithContext(gomock.Any(), input, gomock.Any()).Return(nil, retErr) + retErr := &smithy.GenericAPIError{Code: "PrivateIpAddressLimitExceeded", Message: "Too many IPs already allocated"} + mockEC2.EXPECT().AssignPrivateIpAddresses(gomock.Any(), input, gomock.Any()).Return(nil, retErr) // If EC2 says that all IPs are already attached, then DS is out of sync so alloc will fail _, err := cache.AllocIPAddresses(eniID, 14) assert.Error(t, err) @@ -972,9 +992,9 @@ func TestAllocPrefixAddresses(t *testing.T) { //Allocate 1 prefix for the ENI input := &ec2.AssignPrivateIpAddressesInput{ NetworkInterfaceId: aws.String(eniID), - Ipv4PrefixCount: aws.Int64(1), + Ipv4PrefixCount: aws.Int32(1), } - mockEC2.EXPECT().AssignPrivateIpAddressesWithContext(gomock.Any(), input, gomock.Any()).Return(nil, nil) + mockEC2.EXPECT().AssignPrivateIpAddresses(gomock.Any(), input, gomock.Any()).Return(nil, nil) cache := &EC2InstanceMetadataCache{ec2SVC: mockEC2, instanceType: "c5n.18xlarge", enablePrefixDelegation: true} _, err := cache.AllocIPAddresses(eniID, 1) @@ -991,12 +1011,12 @@ func TestAllocPrefixesAlreadyFull(t *testing.T) { // The required Prefixes (1) is the ENI's limit(1) input := &ec2.AssignPrivateIpAddressesInput{ NetworkInterfaceId: aws.String(eniID), - Ipv4PrefixCount: aws.Int64(1), + Ipv4PrefixCount: aws.Int32(1), } cache := &EC2InstanceMetadataCache{ec2SVC: mockEC2, instanceType: "t3.xlarge", enablePrefixDelegation: true} - retErr := awserr.New("PrivateIpAddressLimitExceeded", "Too many IPs already allocated", nil) - mockEC2.EXPECT().AssignPrivateIpAddressesWithContext(gomock.Any(), input, gomock.Any()).Return(nil, retErr) + retErr := &smithy.GenericAPIError{Code: "PrivateIpAddressLimitExceeded", Message: "Too many IPs already allocated"} + mockEC2.EXPECT().AssignPrivateIpAddresses(gomock.Any(), input, gomock.Any()).Return(nil, retErr) // If EC2 says that all IPs are already attached, then DS is out of sync so alloc will fail _, err := cache.AllocIPAddresses(eniID, 1) assert.Error(t, err) @@ -1044,7 +1064,7 @@ func TestEC2InstanceMetadataCache_waitForENIAndIPsAttached(t *testing.T) { MAC: eni2MAC, DeviceNumber: 1, SubnetIPv4CIDR: subnetCIDR, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { Primary: &isPrimary, PrivateIpAddress: &primaryIP, @@ -1118,13 +1138,13 @@ func TestEC2InstanceMetadataCache_waitForENIAndPrefixesAttached(t *testing.T) { MAC: eni2MAC, DeviceNumber: 1, SubnetIPv4CIDR: subnetCIDR, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { Primary: &isPrimary, PrivateIpAddress: &primaryIP, }, }, - IPv4Prefixes: []*ec2.Ipv4PrefixSpecification{ + IPv4Prefixes: []ec2types.Ipv4PrefixSpecification{ { Ipv4Prefix: &prefixIP, }, @@ -1136,18 +1156,18 @@ func TestEC2InstanceMetadataCache_waitForENIAndPrefixesAttached(t *testing.T) { MAC: eni2MAC, DeviceNumber: 1, SubnetIPv4CIDR: subnetCIDR, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { Primary: &isPrimary, PrivateIpAddress: &primaryIP, }, }, - IPv6Prefixes: []*ec2.Ipv6PrefixSpecification{ + IPv6Prefixes: []ec2types.Ipv6PrefixSpecification{ { Ipv6Prefix: &v6PrefixIP, }, }, - IPv6Addresses: []*ec2.NetworkInterfaceIpv6Address{}, + IPv6Addresses: []ec2types.NetworkInterfaceIpv6Address{}, } tests := []struct { name string @@ -1214,15 +1234,15 @@ func TestEC2InstanceMetadataCache_cleanUpLeakedENIsInternal(t *testing.T) { defer ctrl.Finish() description := eniDescriptionPrefix + "test" - interfaces := []*ec2.NetworkInterface{{ + interfaces := []ec2types.NetworkInterface{{ Description: &description, - TagSet: []*ec2.Tag{ + TagSet: []ec2types.Tag{ {Key: aws.String(eniNodeTagKey), Value: aws.String("test-value")}, }, }} setupDescribeNetworkInterfacesPagesWithContextMock(t, mockEC2, interfaces, nil, 1) - mockEC2.EXPECT().CreateTagsWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + mockEC2.EXPECT().CreateTags(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) cache := &EC2InstanceMetadataCache{ec2SVC: mockEC2} // Test checks that both mocks gets called. @@ -1230,15 +1250,14 @@ func TestEC2InstanceMetadataCache_cleanUpLeakedENIsInternal(t *testing.T) { } func setupDescribeNetworkInterfacesPagesWithContextMock( - t *testing.T, mockEC2 *mock_ec2wrapper.MockEC2, interfaces []*ec2.NetworkInterface, err error, times int) { + t *testing.T, mockEC2 *mock_ec2wrapper.MockEC2, interfaces []ec2types.NetworkInterface, err error, times int) { mockEC2.EXPECT(). - DescribeNetworkInterfacesPagesWithContext(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(times). - DoAndReturn(func(_ context.Context, _ *ec2.DescribeNetworkInterfacesInput, - fn func(*ec2.DescribeNetworkInterfacesOutput, bool) bool, _ ...request.Option) error { - assert.Equal(t, true, fn(&ec2.DescribeNetworkInterfacesOutput{ + DescribeNetworkInterfaces(gomock.Any(), gomock.Any(), gomock.Any()). + Times(times). + DoAndReturn(func(_ context.Context, _ *ec2.DescribeNetworkInterfacesInput, opts ...func(*ec2.Options)) (*ec2.DescribeNetworkInterfacesOutput, error) { + return &ec2.DescribeNetworkInterfacesOutput{ NetworkInterfaces: interfaces, - }, true)) - return err + }, err }) } @@ -1317,7 +1336,7 @@ func TestEC2InstanceMetadataCache_getLeakedENIs(t *testing.T) { tests := []struct { name string fields fields - want []*ec2.NetworkInterface + want []ec2types.NetworkInterface wantErr error }{ { @@ -1327,21 +1346,21 @@ func TestEC2InstanceMetadataCache_getLeakedENIs(t *testing.T) { describeNetworkInterfacePagesCalls: []describeNetworkInterfacePagesCall{ { input: &ec2.DescribeNetworkInterfacesInput{ - Filters: []*ec2.Filter{ + Filters: []ec2types.Filter{ { Name: aws.String("tag-key"), - Values: []*string{aws.String("node.k8s.amazonaws.com/instance_id")}, + Values: []string{"node.k8s.amazonaws.com/instance_id"}, }, { Name: aws.String("status"), - Values: []*string{aws.String("available")}, + Values: []string{"available"}, }, { Name: aws.String("vpc-id"), - Values: []*string{aws.String(vpcID)}, + Values: []string{vpcID}, }, }, - MaxResults: aws.Int64(1000), + MaxResults: aws.Int32(1000), }, outputPages: []*ec2.DescribeNetworkInterfacesOutput{ { @@ -1360,30 +1379,30 @@ func TestEC2InstanceMetadataCache_getLeakedENIs(t *testing.T) { describeNetworkInterfacePagesCalls: []describeNetworkInterfacePagesCall{ { input: &ec2.DescribeNetworkInterfacesInput{ - Filters: []*ec2.Filter{ + Filters: []ec2types.Filter{ { Name: aws.String("tag-key"), - Values: []*string{aws.String("node.k8s.amazonaws.com/instance_id")}, + Values: []string{"node.k8s.amazonaws.com/instance_id"}, }, { Name: aws.String("status"), - Values: []*string{aws.String("available")}, + Values: []string{"available"}, }, { Name: aws.String("vpc-id"), - Values: []*string{aws.String(vpcID)}, + Values: []string{vpcID}, }, }, - MaxResults: aws.Int64(1000), + MaxResults: aws.Int32(1000), }, outputPages: []*ec2.DescribeNetworkInterfacesOutput{ { - NetworkInterfaces: []*ec2.NetworkInterface{ + NetworkInterfaces: []ec2types.NetworkInterface{ { NetworkInterfaceId: aws.String("eni-1"), Description: aws.String("aws-K8S-i-xxxxx"), - Status: aws.String("available"), - TagSet: []*ec2.Tag{ + Status: "available", + TagSet: []ec2types.Tag{ { Key: aws.String("node.k8s.amazonaws.com/instance_id"), Value: aws.String("i-xxxxx"), @@ -1400,12 +1419,12 @@ func TestEC2InstanceMetadataCache_getLeakedENIs(t *testing.T) { }, }, }, - want: []*ec2.NetworkInterface{ + want: []ec2types.NetworkInterface{ { NetworkInterfaceId: aws.String("eni-1"), Description: aws.String("aws-K8S-i-xxxxx"), - Status: aws.String("available"), - TagSet: []*ec2.Tag{ + Status: "available", + TagSet: []ec2types.Tag{ { Key: aws.String("node.k8s.amazonaws.com/instance_id"), Value: aws.String("i-xxxxx"), @@ -1425,30 +1444,30 @@ func TestEC2InstanceMetadataCache_getLeakedENIs(t *testing.T) { describeNetworkInterfacePagesCalls: []describeNetworkInterfacePagesCall{ { input: &ec2.DescribeNetworkInterfacesInput{ - Filters: []*ec2.Filter{ + Filters: []ec2types.Filter{ { Name: aws.String("tag-key"), - Values: []*string{aws.String("node.k8s.amazonaws.com/instance_id")}, + Values: []string{"node.k8s.amazonaws.com/instance_id"}, }, { Name: aws.String("status"), - Values: []*string{aws.String("available")}, + Values: []string{"available"}, }, { Name: aws.String("vpc-id"), - Values: []*string{aws.String(vpcID)}, + Values: []string{vpcID}, }, }, - MaxResults: aws.Int64(1000), + MaxResults: aws.Int32(1000), }, outputPages: []*ec2.DescribeNetworkInterfacesOutput{ { - NetworkInterfaces: []*ec2.NetworkInterface{ + NetworkInterfaces: []ec2types.NetworkInterface{ { NetworkInterfaceId: aws.String("eni-1"), Description: aws.String("non-k8s-i-xxxxx"), - Status: aws.String("available"), - TagSet: []*ec2.Tag{ + Status: "available", + TagSet: []ec2types.Tag{ { Key: aws.String("node.k8s.amazonaws.com/instance_id"), Value: aws.String("i-xxxxx"), @@ -1474,30 +1493,30 @@ func TestEC2InstanceMetadataCache_getLeakedENIs(t *testing.T) { describeNetworkInterfacePagesCalls: []describeNetworkInterfacePagesCall{ { input: &ec2.DescribeNetworkInterfacesInput{ - Filters: []*ec2.Filter{ + Filters: []ec2types.Filter{ { Name: aws.String("tag-key"), - Values: []*string{aws.String("node.k8s.amazonaws.com/instance_id")}, + Values: []string{"node.k8s.amazonaws.com/instance_id"}, }, { Name: aws.String("status"), - Values: []*string{aws.String("available")}, + Values: []string{"available"}, }, { Name: aws.String("vpc-id"), - Values: []*string{aws.String(vpcID)}, + Values: []string{vpcID}, }, }, - MaxResults: aws.Int64(1000), + MaxResults: aws.Int32(1000), }, outputPages: []*ec2.DescribeNetworkInterfacesOutput{ { - NetworkInterfaces: []*ec2.NetworkInterface{ + NetworkInterfaces: []ec2types.NetworkInterface{ { NetworkInterfaceId: aws.String("eni-1"), Description: aws.String("aws-K8S-i-xxxxx"), - Status: aws.String("available"), - TagSet: []*ec2.Tag{ + Status: "available", + TagSet: []ec2types.Tag{ { Key: aws.String("node.k8s.amazonaws.com/instance_id"), Value: aws.String("i-xxxxx"), @@ -1523,21 +1542,21 @@ func TestEC2InstanceMetadataCache_getLeakedENIs(t *testing.T) { describeNetworkInterfacePagesCalls: []describeNetworkInterfacePagesCall{ { input: &ec2.DescribeNetworkInterfacesInput{ - Filters: []*ec2.Filter{ + Filters: []ec2types.Filter{ { Name: aws.String("tag-key"), - Values: []*string{aws.String("node.k8s.amazonaws.com/instance_id")}, + Values: []string{"node.k8s.amazonaws.com/instance_id"}, }, { Name: aws.String("status"), - Values: []*string{aws.String("available")}, + Values: []string{"available"}, }, { Name: aws.String("vpc-id"), - Values: []*string{aws.String(vpcID)}, + Values: []string{vpcID}, }, }, - MaxResults: aws.Int64(1000), + MaxResults: aws.Int32(1000), }, outputPages: []*ec2.DescribeNetworkInterfacesOutput{ { @@ -1556,34 +1575,34 @@ func TestEC2InstanceMetadataCache_getLeakedENIs(t *testing.T) { describeNetworkInterfacePagesCalls: []describeNetworkInterfacePagesCall{ { input: &ec2.DescribeNetworkInterfacesInput{ - Filters: []*ec2.Filter{ + Filters: []ec2types.Filter{ { Name: aws.String("tag-key"), - Values: []*string{aws.String("node.k8s.amazonaws.com/instance_id")}, + Values: []string{"node.k8s.amazonaws.com/instance_id"}, }, { Name: aws.String("status"), - Values: []*string{aws.String("available")}, + Values: []string{"available"}, }, { Name: aws.String("vpc-id"), - Values: []*string{aws.String(vpcID)}, + Values: []string{vpcID}, }, { Name: aws.String("tag:cluster.k8s.amazonaws.com/name"), - Values: []*string{aws.String("awesome-cluster")}, + Values: []string{"awesome-cluster"}, }, }, - MaxResults: aws.Int64(1000), + MaxResults: aws.Int32(1000), }, outputPages: []*ec2.DescribeNetworkInterfacesOutput{ { - NetworkInterfaces: []*ec2.NetworkInterface{ + NetworkInterfaces: []ec2types.NetworkInterface{ { NetworkInterfaceId: aws.String("eni-1"), Description: aws.String("aws-K8S-i-xxxxx"), - Status: aws.String("available"), - TagSet: []*ec2.Tag{ + Status: "available", + TagSet: []ec2types.Tag{ { Key: aws.String("node.k8s.amazonaws.com/instance_id"), Value: aws.String("i-xxxxx"), @@ -1604,12 +1623,12 @@ func TestEC2InstanceMetadataCache_getLeakedENIs(t *testing.T) { }, }, }, - want: []*ec2.NetworkInterface{ + want: []ec2types.NetworkInterface{ { NetworkInterfaceId: aws.String("eni-1"), Description: aws.String("aws-K8S-i-xxxxx"), - Status: aws.String("available"), - TagSet: []*ec2.Tag{ + Status: "available", + TagSet: []ec2types.Tag{ { Key: aws.String("node.k8s.amazonaws.com/instance_id"), Value: aws.String("i-xxxxx"), @@ -1633,34 +1652,34 @@ func TestEC2InstanceMetadataCache_getLeakedENIs(t *testing.T) { describeNetworkInterfacePagesCalls: []describeNetworkInterfacePagesCall{ { input: &ec2.DescribeNetworkInterfacesInput{ - Filters: []*ec2.Filter{ + Filters: []ec2types.Filter{ { Name: aws.String("tag-key"), - Values: []*string{aws.String("node.k8s.amazonaws.com/instance_id")}, + Values: []string{"node.k8s.amazonaws.com/instance_id"}, }, { Name: aws.String("status"), - Values: []*string{aws.String("available")}, + Values: []string{"available"}, }, { Name: aws.String("vpc-id"), - Values: []*string{aws.String(vpcID)}, + Values: []string{vpcID}, }, { Name: aws.String("tag:cluster.k8s.amazonaws.com/name"), - Values: []*string{aws.String("awesome-cluster")}, + Values: []string{"awesome-cluster"}, }, }, - MaxResults: aws.Int64(1000), + MaxResults: aws.Int32(1000), }, outputPages: []*ec2.DescribeNetworkInterfacesOutput{ { - NetworkInterfaces: []*ec2.NetworkInterface{ + NetworkInterfaces: []ec2types.NetworkInterface{ { NetworkInterfaceId: aws.String("eni-1"), Description: aws.String("non-k8s-i-xxxxx"), - Status: aws.String("available"), - TagSet: []*ec2.Tag{ + Status: "available", + TagSet: []ec2types.Tag{ { Key: aws.String("node.k8s.amazonaws.com/instance_id"), Value: aws.String("i-xxxxx"), @@ -1690,34 +1709,34 @@ func TestEC2InstanceMetadataCache_getLeakedENIs(t *testing.T) { describeNetworkInterfacePagesCalls: []describeNetworkInterfacePagesCall{ { input: &ec2.DescribeNetworkInterfacesInput{ - Filters: []*ec2.Filter{ + Filters: []ec2types.Filter{ { Name: aws.String("tag-key"), - Values: []*string{aws.String("node.k8s.amazonaws.com/instance_id")}, + Values: []string{"node.k8s.amazonaws.com/instance_id"}, }, { Name: aws.String("status"), - Values: []*string{aws.String("available")}, + Values: []string{"available"}, }, { Name: aws.String("vpc-id"), - Values: []*string{aws.String(vpcID)}, + Values: []string{vpcID}, }, { Name: aws.String("tag:cluster.k8s.amazonaws.com/name"), - Values: []*string{aws.String("awesome-cluster")}, + Values: []string{"awesome-cluster"}, }, }, - MaxResults: aws.Int64(1000), + MaxResults: aws.Int32(1000), }, outputPages: []*ec2.DescribeNetworkInterfacesOutput{ { - NetworkInterfaces: []*ec2.NetworkInterface{ + NetworkInterfaces: []ec2types.NetworkInterface{ { NetworkInterfaceId: aws.String("eni-1"), Description: aws.String("aws-K8S-i-xxxxx"), - Status: aws.String("available"), - TagSet: []*ec2.Tag{ + Status: "available", + TagSet: []ec2types.Tag{ { Key: aws.String("node.k8s.amazonaws.com/instance_id"), Value: aws.String("i-xxxxx"), @@ -1748,16 +1767,18 @@ func TestEC2InstanceMetadataCache_getLeakedENIs(t *testing.T) { for _, call := range tt.fields.describeNetworkInterfacePagesCalls { mockEC2.EXPECT(). - DescribeNetworkInterfacesPagesWithContext(gomock.Any(), call.input, gomock.Any(), gomock.Any()). - DoAndReturn(func(_ context.Context, _ *ec2.DescribeNetworkInterfacesInput, - fn func(*ec2.DescribeNetworkInterfacesOutput, bool) bool, _ ...request.Option) error { + DescribeNetworkInterfaces(gomock.Any(), call.input, gomock.Any()). + DoAndReturn(func(_ context.Context, _ *ec2.DescribeNetworkInterfacesInput, opts ...func(*ec2.Options)) (*ec2.DescribeNetworkInterfacesOutput, error) { if call.err != nil { - return call.err + return nil, call.err + } + output := &ec2.DescribeNetworkInterfacesOutput{ + NetworkInterfaces: []ec2types.NetworkInterface{}, } - for _, output := range call.outputPages { - fn(output, true) + for _, page := range call.outputPages { + output.NetworkInterfaces = append(output.NetworkInterfaces, page.NetworkInterfaces...) } - return nil + return output, nil }) } cache := &EC2InstanceMetadataCache{ec2SVC: mockEC2, clusterName: tt.fields.clusterName, vpcID: vpcID} @@ -1802,8 +1823,8 @@ func TestEC2InstanceMetadataCache_TagENI(t *testing.T) { createTagsCalls: []createTagsCall{ { input: &ec2.CreateTagsInput{ - Resources: []*string{aws.String("eni-xxxx")}, - Tags: []*ec2.Tag{ + Resources: []string{"eni-xxxx"}, + Tags: []ec2types.Tag{ { Key: aws.String("cluster.k8s.amazonaws.com/name"), Value: aws.String("awesome-cluster"), @@ -1847,8 +1868,8 @@ func TestEC2InstanceMetadataCache_TagENI(t *testing.T) { createTagsCalls: []createTagsCall{ { input: &ec2.CreateTagsInput{ - Resources: []*string{aws.String("eni-xxxx")}, - Tags: []*ec2.Tag{ + Resources: []string{"eni-xxxx"}, + Tags: []ec2types.Tag{ { Key: aws.String("cluster.k8s.amazonaws.com/name"), Value: aws.String("awesome-cluster"), @@ -1875,8 +1896,8 @@ func TestEC2InstanceMetadataCache_TagENI(t *testing.T) { createTagsCalls: []createTagsCall{ { input: &ec2.CreateTagsInput{ - Resources: []*string{aws.String("eni-xxxx")}, - Tags: []*ec2.Tag{ + Resources: []string{"eni-xxxx"}, + Tags: []ec2types.Tag{ { Key: aws.String("cluster.k8s.amazonaws.com/name"), Value: aws.String("awesome-cluster"), @@ -1904,7 +1925,7 @@ func TestEC2InstanceMetadataCache_TagENI(t *testing.T) { defer ctrl.Finish() for _, call := range tt.fields.createTagsCalls { - mockEC2.EXPECT().CreateTagsWithContext(gomock.Any(), call.input).Return(&ec2.CreateTagsOutput{}, call.err).AnyTimes() + mockEC2.EXPECT().CreateTags(gomock.Any(), call.input).Return(&ec2.CreateTagsOutput{}, call.err).AnyTimes() } cache := &EC2InstanceMetadataCache{ @@ -1930,7 +1951,7 @@ func Test_convertTagsToSDKTags(t *testing.T) { tests := []struct { name string args args - want []*ec2.Tag + want []ec2types.Tag }{ { name: "non-empty tags", @@ -1940,7 +1961,7 @@ func Test_convertTagsToSDKTags(t *testing.T) { "keyB": "valueB", }, }, - want: []*ec2.Tag{ + want: []ec2types.Tag{ { Key: aws.String("keyA"), Value: aws.String("valueA"), @@ -1972,7 +1993,7 @@ func Test_convertTagsToSDKTags(t *testing.T) { func Test_convertSDKTagsToTags(t *testing.T) { type args struct { - sdkTags []*ec2.Tag + sdkTags []ec2types.Tag } tests := []struct { name string @@ -1982,7 +2003,7 @@ func Test_convertSDKTagsToTags(t *testing.T) { { name: "non-empty sdk tags", args: args{ - sdkTags: []*ec2.Tag{ + sdkTags: []ec2types.Tag{ { Key: aws.String("keyA"), Value: aws.String("valueA"), @@ -2008,14 +2029,14 @@ func Test_convertSDKTagsToTags(t *testing.T) { { name: "empty sdk tags", args: args{ - sdkTags: []*ec2.Tag{}, + sdkTags: []ec2types.Tag{}, }, want: nil, }, { name: "nil sdk tag value", args: args{ - sdkTags: []*ec2.Tag{ + sdkTags: []ec2types.Tag{ { Key: aws.String("keyA"), Value: nil, diff --git a/pkg/awsutils/imds.go b/pkg/awsutils/imds.go index ab845eeb45..0c3152442c 100644 --- a/pkg/awsutils/imds.go +++ b/pkg/awsutils/imds.go @@ -16,18 +16,22 @@ package awsutils import ( "context" "fmt" + "io" "net" "net/http" "strconv" "strings" - "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/smithy-go" + + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" "github.com/pkg/errors" ) // EC2MetadataIface is a subset of the EC2Metadata API. type EC2MetadataIface interface { - GetMetadataWithContext(ctx context.Context, p string) (string, error) + GetMetadata(ctx context.Context, params *imds.GetMetadataInput, optFns ...func(*imds.Options)) (*imds.GetMetadataOutput, error) } // TypedIMDS is a typed wrapper around raw untyped IMDS SDK API. @@ -39,6 +43,8 @@ type TypedIMDS struct { type imdsRequestError struct { requestKey string err error + code string // Added to support SDK V2 APIError interface + fault smithy.ErrorFault // Added to support SDK V2 APIError interface } var _ error = &imdsRequestError{} @@ -47,6 +53,8 @@ func newIMDSRequestError(requestKey string, err error) *imdsRequestError { return &imdsRequestError{ requestKey: requestKey, err: err, + code: "IMDSRequestError", // default code + fault: smithy.FaultUnknown, // default fault } } @@ -54,78 +62,160 @@ func (e *imdsRequestError) Error() string { return fmt.Sprintf("failed to retrieve %s from instance metadata %v", e.requestKey, e.err) } -func (imds TypedIMDS) getList(ctx context.Context, key string) ([]string, error) { - data, err := imds.GetMetadataWithContext(ctx, key) +func (e *imdsRequestError) Unwrap() error { + return e.err +} + +// Implement smithy.APIError interface + +func (e *imdsRequestError) ErrorCode() string { + // If wrapped error is an APIError, delegate to it + var apiErr smithy.APIError + if errors.As(e.err, &apiErr) { + return apiErr.ErrorCode() + } + return e.code +} + +func (e *imdsRequestError) ErrorMessage() string { + return e.Error() +} + +func (e *imdsRequestError) ErrorFault() smithy.ErrorFault { + // If wrapped error is an APIError, delegate to it + var apiErr smithy.APIError + if errors.As(e.err, &apiErr) { + return apiErr.ErrorFault() + } + return e.fault +} + +func (e *imdsRequestError) HTTPStatusCode() int { + if resp, ok := e.err.(interface{ HTTPStatusCode() int }); ok { + return resp.HTTPStatusCode() + } + return 200 +} + +func (e *imdsRequestError) RequestID() string { + if resp, ok := e.err.(interface{ RequestID() string }); ok { + return resp.RequestID() + } + return "" +} + +func (typedimds TypedIMDS) getList(ctx context.Context, key string) ([]string, error) { + output, err := typedimds.GetMetadata(ctx, &imds.GetMetadataInput{ + Path: key, + }) if err != nil { return nil, err } - return strings.Fields(data), err + if output == nil || output.Content == nil { + return nil, newIMDSRequestError(key, fmt.Errorf("empty response")) + } + + defer output.Content.Close() + bytes, err := io.ReadAll(output.Content) + if err != nil { + return nil, newIMDSRequestError(key, fmt.Errorf("failed to read content: %w", err)) + } + + return strings.Fields(string(bytes)), nil } // GetAZ returns the Availability Zone in which the instance launched. -func (imds TypedIMDS) GetAZ(ctx context.Context) (string, error) { - az, err := imds.GetMetadataWithContext(ctx, "placement/availability-zone") +func (typedimds TypedIMDS) GetAZ(ctx context.Context) (string, error) { + output, err := typedimds.GetMetadata(ctx, &imds.GetMetadataInput{ + Path: "placement/availability-zone"}) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - log.Warnf("%v", err) - return az, imdsErr.err - } return "", err } - return az, err + if output == nil || output.Content == nil { + return "", newIMDSRequestError("placement/availability-zone", fmt.Errorf("empty response")) + } + + defer output.Content.Close() + bytes, err := io.ReadAll(output.Content) + if err != nil { + return "", newIMDSRequestError("placement/availability-zone", fmt.Errorf("failed to read content: %w", err)) + } + return strings.TrimSpace(string(bytes)), nil } // GetInstanceType returns the type of this instance. -func (imds TypedIMDS) GetInstanceType(ctx context.Context) (string, error) { - instanceType, err := imds.GetMetadataWithContext(ctx, "instance-type") +func (typedimds TypedIMDS) GetInstanceType(ctx context.Context) (string, error) { + output, err := typedimds.GetMetadata(ctx, &imds.GetMetadataInput{ + Path: "instance-type"}) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - log.Warnf("%v", err) - return instanceType, imdsErr.err - } return "", err } - return instanceType, err + + if output == nil || output.Content == nil { + return "", newIMDSRequestError("instance-type", fmt.Errorf("empty response")) + } + + defer output.Content.Close() + bytes, err := io.ReadAll(output.Content) + if err != nil { + return "", newIMDSRequestError("instance-type", fmt.Errorf("failed to read content: %w", err)) + } + return strings.TrimSpace(string(bytes)), nil } // GetLocalIPv4 returns the private (primary) IPv4 address of the instance. -func (imds TypedIMDS) GetLocalIPv4(ctx context.Context) (net.IP, error) { - return imds.getIP(ctx, "local-ipv4") +func (typedimds TypedIMDS) GetLocalIPv4(ctx context.Context) (net.IP, error) { + return typedimds.getIP(ctx, "local-ipv4") } // GetInstanceID returns the ID of this instance. -func (imds TypedIMDS) GetInstanceID(ctx context.Context) (string, error) { - instanceID, err := imds.GetMetadataWithContext(ctx, "instance-id") +func (typedimds TypedIMDS) GetInstanceID(ctx context.Context) (string, error) { + output, err := typedimds.GetMetadata(ctx, &imds.GetMetadataInput{ + Path: "instance-id"}) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - log.Warnf("%v", err) - return instanceID, imdsErr.err - } return "", err } - return instanceID, err + + if output == nil || output.Content == nil { + return "", newIMDSRequestError("instance-id", fmt.Errorf("empty response")) + } + + defer output.Content.Close() + bytes, err := io.ReadAll(output.Content) + if err != nil { + return "", newIMDSRequestError("instance-id", fmt.Errorf("failed to read content: %w", err)) + } + return strings.TrimSpace(string(bytes)), nil } // GetMAC returns the first/primary network interface mac address. -func (imds TypedIMDS) GetMAC(ctx context.Context) (string, error) { - mac, err := imds.GetMetadataWithContext(ctx, "mac") +func (typedimds TypedIMDS) GetMAC(ctx context.Context) (string, error) { + output, err := typedimds.GetMetadata(ctx, &imds.GetMetadataInput{ + Path: "mac"}) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - log.Warnf("%v", err) - return mac, imdsErr.err - } return "", err } - return mac, err + if output == nil || output.Content == nil { + return "", newIMDSRequestError("mac", fmt.Errorf("empty response")) + } + + defer output.Content.Close() + bytes, err := io.ReadAll(output.Content) + if err != nil { + return "", newIMDSRequestError("mac", fmt.Errorf("failed to read content: %w", err)) + } + return string(bytes), nil } // GetMACs returns the interface addresses attached to the instance. -func (imds TypedIMDS) GetMACs(ctx context.Context) ([]string, error) { - list, err := imds.getList(ctx, "network/interfaces/macs") +func (typedimds TypedIMDS) GetMACs(ctx context.Context) ([]string, error) { + list, err := typedimds.getList(ctx, "network/interfaces/macs") if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { + imdsErr := new(imdsRequestError) + oe := new(smithy.OperationError) + if errors.As(err, &imdsErr) || errors.As(err, &oe) { log.Warnf("%v", err) - return nil, imdsErr.err + return nil, newIMDSRequestError(err.Error(), err) } return nil, err } @@ -137,11 +227,13 @@ func (imds TypedIMDS) GetMACs(ctx context.Context) ([]string, error) { } // GetMACImdsFields returns the imds fields present for a MAC -func (imds TypedIMDS) GetMACImdsFields(ctx context.Context, mac string) ([]string, error) { +func (typedimds TypedIMDS) GetMACImdsFields(ctx context.Context, mac string) ([]string, error) { key := fmt.Sprintf("network/interfaces/macs/%s", mac) - list, err := imds.getList(ctx, key) + list, err := typedimds.getList(ctx, key) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { + imdsErr := new(imdsRequestError) + oe := new(smithy.OperationError) + if errors.As(err, &imdsErr) || errors.As(err, &oe) { log.Warnf("%v", err) return nil, imdsErr.err } @@ -155,29 +247,41 @@ func (imds TypedIMDS) GetMACImdsFields(ctx context.Context, mac string) ([]strin } // GetInterfaceID returns the ID of the network interface. -func (imds TypedIMDS) GetInterfaceID(ctx context.Context, mac string) (string, error) { +func (typedimds TypedIMDS) GetInterfaceID(ctx context.Context, mac string) (string, error) { key := fmt.Sprintf("network/interfaces/macs/%s/interface-id", mac) - interfaceID, err := imds.GetMetadataWithContext(ctx, key) + output, err := typedimds.GetMetadata(ctx, &imds.GetMetadataInput{ + Path: key}) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - log.Warnf("%v", err) - return interfaceID, imdsErr.err - } return "", err } - return interfaceID, err + if output == nil || output.Content == nil { + return "", newIMDSRequestError(key, fmt.Errorf("empty response")) + } + + defer output.Content.Close() + bytes, err := io.ReadAll(output.Content) + if err != nil { + return "", newIMDSRequestError(key, fmt.Errorf("failed to read content: %w", err)) + } + return string(bytes), nil } -func (imds TypedIMDS) getInt(ctx context.Context, key string) (int, error) { - data, err := imds.GetMetadataWithContext(ctx, key) +func (typedimds TypedIMDS) getInt(ctx context.Context, key string) (int, error) { + output, err := typedimds.GetMetadata(ctx, &imds.GetMetadataInput{ + Path: key}) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - log.Warnf("%v", err) - return 0, imdsErr.err - } return 0, err } - dataInt, err := strconv.Atoi(data) + if output == nil || output.Content == nil { + return 0, newIMDSRequestError(key, fmt.Errorf("empty response")) + } + + defer output.Content.Close() + bytes, err := io.ReadAll(output.Content) + if err != nil { + return 0, newIMDSRequestError(key, fmt.Errorf("failed to read content: %w", err)) + } + dataInt, err := strconv.Atoi(strings.TrimSpace(string(bytes))) if err != nil { return 0, err } @@ -185,72 +289,112 @@ func (imds TypedIMDS) getInt(ctx context.Context, key string) (int, error) { } // GetDeviceNumber returns the unique device number associated with an interface. The primary interface is 0. -func (imds TypedIMDS) GetDeviceNumber(ctx context.Context, mac string) (int, error) { +func (typedimds TypedIMDS) GetDeviceNumber(ctx context.Context, mac string) (int, error) { key := fmt.Sprintf("network/interfaces/macs/%s/device-number", mac) - return imds.getInt(ctx, key) + return typedimds.getInt(ctx, key) } // GetSubnetID returns the ID of the subnet in which the interface resides. -func (imds TypedIMDS) GetSubnetID(ctx context.Context, mac string) (string, error) { +func (typedimds TypedIMDS) GetSubnetID(ctx context.Context, mac string) (string, error) { key := fmt.Sprintf("network/interfaces/macs/%s/subnet-id", mac) - subnetID, err := imds.GetMetadataWithContext(ctx, key) + output, err := typedimds.GetMetadata(ctx, &imds.GetMetadataInput{ + Path: key, + }) + + // Read the content first, even if there's an error + var subnetID string + if output != nil && output.Content != nil { + defer output.Content.Close() + bytes, readErr := io.ReadAll(output.Content) + if readErr == nil { + subnetID = string(bytes) + } + } + + // Now handle any errors, but return subnetID if it was read if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - log.Warnf("%v", err) - return subnetID, imdsErr.err + imdsErr := new(imdsRequestError) + oe := new(smithy.OperationError) + if errors.As(err, &imdsErr) || errors.As(err, &oe) { + log.Warnf("Warning: %v", err) + return subnetID, newIMDSRequestError(err.Error(), err) } return "", err } - return subnetID, err + + return subnetID, nil } -func (imds TypedIMDS) GetVpcID(ctx context.Context, mac string) (string, error) { +func (typedimds TypedIMDS) GetVpcID(ctx context.Context, mac string) (string, error) { key := fmt.Sprintf("network/interfaces/macs/%s/vpc-id", mac) - vpcID, err := imds.GetMetadataWithContext(ctx, key) + output, err := typedimds.GetMetadata(ctx, &imds.GetMetadataInput{ + Path: key, + }) + + // Read the content first, even if there's an error + var vpcID string + if output != nil && output.Content != nil { + defer output.Content.Close() + bytes, readErr := io.ReadAll(output.Content) + if readErr == nil { + vpcID = string(bytes) + } + } + + // Handle errors but preserve any partial vpcID data if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - log.Warnf("%v", err) - return vpcID, imdsErr.err + imdsErr := new(imdsRequestError) + oe := new(smithy.OperationError) + if errors.As(err, &imdsErr) || errors.As(err, &oe) { + log.Warnf("Warning: %v", err) + return vpcID, newIMDSRequestError(err.Error(), err) } return "", err } - return vpcID, err + + return vpcID, nil } // GetSecurityGroupIDs returns the IDs of the security groups to which the network interface belongs. -func (imds TypedIMDS) GetSecurityGroupIDs(ctx context.Context, mac string) ([]string, error) { +func (typedimds TypedIMDS) GetSecurityGroupIDs(ctx context.Context, mac string) ([]string, error) { key := fmt.Sprintf("network/interfaces/macs/%s/security-group-ids", mac) - sgs, err := imds.getList(ctx, key) + sgs, err := typedimds.getList(ctx, key) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { + imdsErr := new(imdsRequestError) + oe := new(smithy.OperationError) + if errors.As(err, &imdsErr) || errors.As(err, &oe) { log.Warnf("%v", err) - return sgs, imdsErr.err + return sgs, newIMDSRequestError(err.Error(), err) } return nil, err } return sgs, err } -func (imds TypedIMDS) getIP(ctx context.Context, key string) (net.IP, error) { - data, err := imds.GetMetadataWithContext(ctx, key) +func (typedimds TypedIMDS) getIP(ctx context.Context, key string) (net.IP, error) { + output, err := typedimds.GetMetadata(ctx, &imds.GetMetadataInput{ + Path: key}) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - log.Warnf("%v", err) - return nil, imdsErr.err - } return nil, err } + if output == nil || output.Content == nil { + return nil, newIMDSRequestError(key, fmt.Errorf("empty response")) + } - ip := net.ParseIP(data) + defer output.Content.Close() + bytes, err := io.ReadAll(output.Content) + if err != nil { + return nil, newIMDSRequestError(key, fmt.Errorf("failed to read content: %w", err)) + } + ip := net.ParseIP(strings.TrimSpace(string(bytes))) if ip == nil { - err = &net.ParseError{Type: "IP address", Text: data} - return nil, err + err = &net.ParseError{Type: "IP address", Text: string(bytes)} } return ip, err } -func (imds TypedIMDS) getIPs(ctx context.Context, key string) ([]net.IP, error) { - list, err := imds.getList(ctx, key) +func (typedimds TypedIMDS) getIPs(ctx context.Context, key string) ([]net.IP, error) { + list, err := typedimds.getList(ctx, key) if err != nil { return nil, err } @@ -267,16 +411,23 @@ func (imds TypedIMDS) getIPs(ctx context.Context, key string) ([]net.IP, error) return ips, err } -func (imds TypedIMDS) getCIDR(ctx context.Context, key string) (net.IPNet, error) { - data, err := imds.GetMetadataWithContext(ctx, key) +func (typedimds TypedIMDS) getCIDR(ctx context.Context, key string) (net.IPNet, error) { + output, err := typedimds.GetMetadata(ctx, &imds.GetMetadataInput{ + Path: key}) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - log.Warnf("%v", err) - return net.IPNet{}, imdsErr.err - } return net.IPNet{}, err } + if output == nil || output.Content == nil { + return net.IPNet{}, newIMDSRequestError(key, fmt.Errorf("empty response")) + } + + defer output.Content.Close() + bytes, err := io.ReadAll(output.Content) + if err != nil { + return net.IPNet{}, newIMDSRequestError(key, fmt.Errorf("failed to read content: %w", err)) + } + data := strings.TrimSpace(string(bytes)) ip, network, err := net.ParseCIDR(data) if err != nil { return net.IPNet{}, err @@ -286,8 +437,8 @@ func (imds TypedIMDS) getCIDR(ctx context.Context, key string) (net.IPNet, error return cidr, err } -func (imds TypedIMDS) getCIDRs(ctx context.Context, key string) ([]net.IPNet, error) { - list, err := imds.getList(ctx, key) +func (typedimds TypedIMDS) getCIDRs(ctx context.Context, key string) ([]net.IPNet, error) { + list, err := typedimds.getList(ctx, key) if err != nil { return nil, err } @@ -305,13 +456,15 @@ func (imds TypedIMDS) getCIDRs(ctx context.Context, key string) ([]net.IPNet, er } // GetLocalIPv4s returns the private IPv4 addresses associated with the interface. First returned address is the primary address. -func (imds TypedIMDS) GetLocalIPv4s(ctx context.Context, mac string) ([]net.IP, error) { +func (typedimds TypedIMDS) GetLocalIPv4s(ctx context.Context, mac string) ([]net.IP, error) { key := fmt.Sprintf("network/interfaces/macs/%s/local-ipv4s", mac) - ips, err := imds.getIPs(ctx, key) + ips, err := typedimds.getIPs(ctx, key) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { + imdsErr := new(imdsRequestError) + oe := new(smithy.OperationError) + if errors.As(err, &imdsErr) || errors.As(err, &oe) { log.Warnf("%v", err) - return nil, imdsErr.err + return nil, newIMDSRequestError(err.Error(), err) } return nil, err } @@ -319,16 +472,19 @@ func (imds TypedIMDS) GetLocalIPv4s(ctx context.Context, mac string) ([]net.IP, } // GetIPv4Prefixes returns the IPv4 prefixes delegated to this interface -func (imds TypedIMDS) GetIPv4Prefixes(ctx context.Context, mac string) ([]net.IPNet, error) { +func (typedimds TypedIMDS) GetIPv4Prefixes(ctx context.Context, mac string) ([]net.IPNet, error) { key := fmt.Sprintf("network/interfaces/macs/%s/ipv4-prefix", mac) - prefixes, err := imds.getCIDRs(ctx, key) + prefixes, err := typedimds.getCIDRs(ctx, key) + if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - if IsNotFound(imdsErr.err) { + imdsErr := new(imdsRequestError) + oe := new(smithy.OperationError) + if errors.As(err, &imdsErr) || errors.As(err, &oe) { + if IsNotFound(err) { return nil, nil } log.Warnf("%v", err) - return nil, imdsErr.err + return nil, newIMDSRequestError(err.Error(), err) } return nil, err } @@ -336,16 +492,18 @@ func (imds TypedIMDS) GetIPv4Prefixes(ctx context.Context, mac string) ([]net.IP } // GetIPv6Prefixes returns the IPv6 prefixes delegated to this interface -func (imds TypedIMDS) GetIPv6Prefixes(ctx context.Context, mac string) ([]net.IPNet, error) { +func (typedimds TypedIMDS) GetIPv6Prefixes(ctx context.Context, mac string) ([]net.IPNet, error) { key := fmt.Sprintf("network/interfaces/macs/%s/ipv6-prefix", mac) - prefixes, err := imds.getCIDRs(ctx, key) + prefixes, err := typedimds.getCIDRs(ctx, key) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - if IsNotFound(imdsErr.err) { + imdsErr := new(imdsRequestError) + oe := new(smithy.OperationError) + if errors.As(err, &imdsErr) || errors.As(err, &oe) { + if IsNotFound(err) { return nil, nil } log.Warnf("%v", err) - return nil, imdsErr.err + return nil, newIMDSRequestError(err.Error(), err) } return nil, err } @@ -353,17 +511,19 @@ func (imds TypedIMDS) GetIPv6Prefixes(ctx context.Context, mac string) ([]net.IP } // GetIPv6s returns the IPv6 addresses associated with the interface. -func (imds TypedIMDS) GetIPv6s(ctx context.Context, mac string) ([]net.IP, error) { +func (typedimds TypedIMDS) GetIPv6s(ctx context.Context, mac string) ([]net.IP, error) { key := fmt.Sprintf("network/interfaces/macs/%s/ipv6s", mac) - ips, err := imds.getIPs(ctx, key) + ips, err := typedimds.getIPs(ctx, key) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - if IsNotFound(imdsErr.err) { + imdsErr := new(imdsRequestError) + oe := new(smithy.OperationError) + if errors.As(err, &imdsErr) || errors.As(err, &oe) { + if IsNotFound(err) { // No IPv6. Not an error, just a disappointment :( return nil, nil } log.Warnf("%v", err) - return nil, imdsErr.err + return nil, newIMDSRequestError(err.Error(), err) } return nil, err } @@ -371,19 +531,21 @@ func (imds TypedIMDS) GetIPv6s(ctx context.Context, mac string) ([]net.IP, error } // GetSubnetIPv4CIDRBlock returns the IPv4 CIDR block for the subnet in which the interface resides. -func (imds TypedIMDS) GetSubnetIPv4CIDRBlock(ctx context.Context, mac string) (net.IPNet, error) { +func (typedimds TypedIMDS) GetSubnetIPv4CIDRBlock(ctx context.Context, mac string) (net.IPNet, error) { key := fmt.Sprintf("network/interfaces/macs/%s/subnet-ipv4-cidr-block", mac) - return imds.getCIDR(ctx, key) + return typedimds.getCIDR(ctx, key) } // GetVPCIPv4CIDRBlocks returns the IPv4 CIDR blocks for the VPC. -func (imds TypedIMDS) GetVPCIPv4CIDRBlocks(ctx context.Context, mac string) ([]net.IPNet, error) { +func (typedimds TypedIMDS) GetVPCIPv4CIDRBlocks(ctx context.Context, mac string) ([]net.IPNet, error) { key := fmt.Sprintf("network/interfaces/macs/%s/vpc-ipv4-cidr-blocks", mac) - cidrs, err := imds.getCIDRs(ctx, key) + cidrs, err := typedimds.getCIDRs(ctx, key) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { + imdsErr := new(imdsRequestError) + oe := new(smithy.OperationError) + if errors.As(err, &imdsErr) || errors.As(err, &oe) { log.Warnf("%v", err) - return cidrs, imdsErr.err + return cidrs, newIMDSRequestError(err.Error(), err) } return nil, err } @@ -391,17 +553,19 @@ func (imds TypedIMDS) GetVPCIPv4CIDRBlocks(ctx context.Context, mac string) ([]n } // GetVPCIPv6CIDRBlocks returns the IPv6 CIDR blocks for the VPC. -func (imds TypedIMDS) GetVPCIPv6CIDRBlocks(ctx context.Context, mac string) ([]net.IPNet, error) { +func (typedimds TypedIMDS) GetVPCIPv6CIDRBlocks(ctx context.Context, mac string) ([]net.IPNet, error) { key := fmt.Sprintf("network/interfaces/macs/%s/vpc-ipv6-cidr-blocks", mac) - ipnets, err := imds.getCIDRs(ctx, key) + ipnets, err := typedimds.getCIDRs(ctx, key) if err != nil { - if imdsErr, ok := err.(*imdsRequestError); ok { - if IsNotFound(imdsErr.err) { + imdsErr := new(imdsRequestError) + oe := new(smithy.OperationError) + if errors.As(err, &imdsErr) || errors.As(err, &oe) { + if IsNotFound(err) { // No IPv6. Not an error, just a disappointment :( return nil, nil } log.Warnf("%v", err) - return nil, imdsErr.err + return nil, newIMDSRequestError(err.Error(), err) } return nil, nil } @@ -409,25 +573,107 @@ func (imds TypedIMDS) GetVPCIPv6CIDRBlocks(ctx context.Context, mac string) ([]n } // GetSubnetIPv6CIDRBlocks returns the IPv6 CIDR block for the subnet in which the interface resides. -func (imds TypedIMDS) GetSubnetIPv6CIDRBlocks(ctx context.Context, mac string) (net.IPNet, error) { +func (typedimds TypedIMDS) GetSubnetIPv6CIDRBlocks(ctx context.Context, mac string) (net.IPNet, error) { key := fmt.Sprintf("network/interfaces/macs/%s/subnet-ipv6-cidr-blocks", mac) - return imds.getCIDR(ctx, key) + return typedimds.getCIDR(ctx, key) } // IsNotFound returns true if the error was caused by an AWS API 404 response. +// We implement a Custom IMDS Error, so need to use APIError instead of HTTP Response Error func IsNotFound(err error) bool { - if err != nil { - var aerr awserr.RequestFailure - if errors.As(err, &aerr) { - return aerr.StatusCode() == http.StatusNotFound + if err == nil { + return false + } + + // Check for AWS ResponseError first + var re *awshttp.ResponseError + if errors.As(err, &re) { + return re.Response.StatusCode == http.StatusNotFound + } + + var oe *smithy.OperationError + if errors.As(err, &oe) { + // Check if the error message contains status code 404 + return strings.Contains(oe.Error(), "StatusCode: 404") + } + + // Check for any APIError (including imdsRequestError) + var ae smithy.APIError + if errors.As(err, &ae) { + // If it's our custom error with a wrapped ResponseError, check that + if imdsErr, ok := ae.(*imdsRequestError); ok { + return IsNotFound(imdsErr.err) } + // Otherwise check if the error code indicates NotFound + return ae.ErrorCode() == "NotFound" } + return false } // FakeIMDS is a trivial implementation of EC2MetadataIface using an in-memory map - for testing. type FakeIMDS map[string]interface{} +func (f FakeIMDS) GetMetadata(ctx context.Context, params *imds.GetMetadataInput, optFns ...func(*imds.Options)) (*imds.GetMetadataOutput, error) { + result, ok := f[params.Path] + if !ok { + result, ok = f[params.Path+"/"] // Metadata API treats foo/ as foo + } + if !ok { + notFoundErr := &CustomRequestFailure{ + code: "NotFound", + message: "not found", + fault: smithy.FaultUnknown, + statusCode: http.StatusNotFound, + requestID: "dummy-reqid", + } + return nil, newIMDSRequestError(params.Path, notFoundErr) + } + switch v := result.(type) { + case string: + return &imds.GetMetadataOutput{ + Content: io.NopCloser(strings.NewReader(v)), + }, nil + case error: + return nil, v + default: + panic(fmt.Sprintf("unknown test metadata value type %T for %s", result, params.Path)) + } +} + +// Custom error type +type CustomRequestFailure struct { + code string + message string + fault smithy.ErrorFault + statusCode int + requestID string +} + +func (e *CustomRequestFailure) Error() string { + return fmt.Sprintf("%s: %s", e.code, e.message) +} + +func (e *CustomRequestFailure) ErrorCode() string { + return e.code +} + +func (e *CustomRequestFailure) ErrorMessage() string { + return e.message +} + +func (e *CustomRequestFailure) ErrorFault() smithy.ErrorFault { + return e.fault +} + +func (e *CustomRequestFailure) HTTPStatusCode() int { + return e.statusCode +} + +func (e *CustomRequestFailure) RequestID() string { + return e.requestID +} + // GetMetadataWithContext implements the EC2MetadataIface interface. func (f FakeIMDS) GetMetadataWithContext(ctx context.Context, p string) (string, error) { result, ok := f[p] @@ -435,7 +681,13 @@ func (f FakeIMDS) GetMetadataWithContext(ctx context.Context, p string) (string, result, ok = f[p+"/"] // Metadata API treats foo/ as foo } if !ok { - notFoundErr := awserr.NewRequestFailure(awserr.New("NotFound", "not found", nil), http.StatusNotFound, "dummy-reqid") + notFoundErr := &CustomRequestFailure{ + code: "NotFound", + message: "not found", + fault: smithy.FaultUnknown, + statusCode: http.StatusNotFound, + requestID: "dummy-reqid", + } return "", newIMDSRequestError(p, notFoundErr) } switch v := result.(type) { diff --git a/pkg/awsutils/mocks/awsutils_mocks.go b/pkg/awsutils/mocks/awsutils_mocks.go index 4e71a57549..7cefc58316 100644 --- a/pkg/awsutils/mocks/awsutils_mocks.go +++ b/pkg/awsutils/mocks/awsutils_mocks.go @@ -22,11 +22,11 @@ import ( net "net" reflect "reflect" - "github.com/aws/amazon-vpc-cni-k8s/pkg/ipamd/datastore" - awsutils "github.com/aws/amazon-vpc-cni-k8s/pkg/awsutils" + datastore "github.com/aws/amazon-vpc-cni-k8s/pkg/ipamd/datastore" vpc "github.com/aws/amazon-vpc-cni-k8s/pkg/vpc" - ec2 "github.com/aws/aws-sdk-go/service/ec2" + ec2 "github.com/aws/aws-sdk-go-v2/service/ec2" + types "github.com/aws/aws-sdk-go-v2/service/ec2/types" gomock "github.com/golang/mock/gomock" ) @@ -227,10 +227,10 @@ func (mr *MockAPIsMockRecorder) GetENILimit() *gomock.Call { } // GetIPv4PrefixesFromEC2 mocks base method. -func (m *MockAPIs) GetIPv4PrefixesFromEC2(arg0 string) ([]*ec2.Ipv4PrefixSpecification, error) { +func (m *MockAPIs) GetIPv4PrefixesFromEC2(arg0 string) ([]types.Ipv4PrefixSpecification, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetIPv4PrefixesFromEC2", arg0) - ret0, _ := ret[0].([]*ec2.Ipv4PrefixSpecification) + ret0, _ := ret[0].([]types.Ipv4PrefixSpecification) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -242,10 +242,10 @@ func (mr *MockAPIsMockRecorder) GetIPv4PrefixesFromEC2(arg0 interface{}) *gomock } // GetIPv4sFromEC2 mocks base method. -func (m *MockAPIs) GetIPv4sFromEC2(arg0 string) ([]*ec2.NetworkInterfacePrivateIpAddress, error) { +func (m *MockAPIs) GetIPv4sFromEC2(arg0 string) ([]types.NetworkInterfacePrivateIpAddress, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetIPv4sFromEC2", arg0) - ret0, _ := ret[0].([]*ec2.NetworkInterfacePrivateIpAddress) + ret0, _ := ret[0].([]types.NetworkInterfacePrivateIpAddress) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -257,10 +257,10 @@ func (mr *MockAPIsMockRecorder) GetIPv4sFromEC2(arg0 interface{}) *gomock.Call { } // GetIPv6PrefixesFromEC2 mocks base method. -func (m *MockAPIs) GetIPv6PrefixesFromEC2(arg0 string) ([]*ec2.Ipv6PrefixSpecification, error) { +func (m *MockAPIs) GetIPv6PrefixesFromEC2(arg0 string) ([]types.Ipv6PrefixSpecification, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetIPv6PrefixesFromEC2", arg0) - ret0, _ := ret[0].([]*ec2.Ipv6PrefixSpecification) + ret0, _ := ret[0].([]types.Ipv6PrefixSpecification) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -468,17 +468,17 @@ func (mr *MockAPIsMockRecorder) IsUnmanagedENI(arg0 interface{}) *gomock.Call { } // RefreshSGIDs mocks base method. -func (m *MockAPIs) RefreshSGIDs(mac string, store *datastore.DataStore) error { +func (m *MockAPIs) RefreshSGIDs(arg0 string, arg1 *datastore.DataStore) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RefreshSGIDs", mac, store) + ret := m.ctrl.Call(m, "RefreshSGIDs", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } // RefreshSGIDs indicates an expected call of RefreshSGIDs. -func (mr *MockAPIsMockRecorder) RefreshSGIDs(mac, store interface{}) *gomock.Call { +func (mr *MockAPIsMockRecorder) RefreshSGIDs(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RefreshSGIDs", reflect.TypeOf((*MockAPIs)(nil).RefreshSGIDs), mac, store) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RefreshSGIDs", reflect.TypeOf((*MockAPIs)(nil).RefreshSGIDs), arg0, arg1) } // SetMultiCardENIs mocks base method. diff --git a/pkg/ec2metadatawrapper/ec2metadatawrapper.go b/pkg/ec2metadatawrapper/ec2metadatawrapper.go index 262c1a60e0..196adf3b22 100644 --- a/pkg/ec2metadatawrapper/ec2metadatawrapper.go +++ b/pkg/ec2metadatawrapper/ec2metadatawrapper.go @@ -2,22 +2,22 @@ package ec2metadatawrapper import ( - "github.com/aws/aws-sdk-go/aws/ec2metadata" - "github.com/aws/aws-sdk-go/aws/session" -) + "context" -// TODO: Move away from using mock + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" +) // HTTPClient is used to help with testing type HTTPClient interface { - GetInstanceIdentityDocument() (ec2metadata.EC2InstanceIdentityDocument, error) - Region() (string, error) + GetInstanceIdentityDocument(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) + GetRegion(ctx context.Context, params *imds.GetRegionInput, optFns ...func(*imds.Options)) (*imds.GetRegionOutput, error) } // EC2MetadataClient to used to obtain a subset of information from EC2 IMDS type EC2MetadataClient interface { - GetInstanceIdentityDocument() (ec2metadata.EC2InstanceIdentityDocument, error) - Region() (string, error) + GetInstanceIdentityDocument(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) + GetRegion(ctx context.Context, params *imds.GetRegionInput, optFns ...func(*imds.Options)) (*imds.GetRegionOutput, error) } type ec2MetadataClientImpl struct { @@ -25,22 +25,27 @@ type ec2MetadataClientImpl struct { } // New creates an ec2metadata client to retrieve metadata -func New(session *session.Session) EC2MetadataClient { - metadata := ec2metadata.New(session) - return NewMetadataService(metadata) +func New(ctx context.Context) (EC2MetadataClient, error) { + cfg, err := config.LoadDefaultConfig(ctx) + if err != nil { + return nil, err + } + + client := imds.NewFromConfig(cfg) + return NewMetadataService(client), nil } // NewMetadataService creates an ec2metadata client to retrieve metadata -func NewMetadataService(metadata HTTPClient) EC2MetadataClient { - return &ec2MetadataClientImpl{client: metadata} +func NewMetadataService(client HTTPClient) EC2MetadataClient { + return &ec2MetadataClientImpl{client: client} } -// InstanceIdentityDocument returns instance identity documents -// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html -func (c *ec2MetadataClientImpl) GetInstanceIdentityDocument() (ec2metadata.EC2InstanceIdentityDocument, error) { - return c.client.GetInstanceIdentityDocument() +// GetInstanceIdentityDocument returns instance identity documents +func (c *ec2MetadataClientImpl) GetInstanceIdentityDocument(ctx context.Context, params *imds.GetInstanceIdentityDocumentInput, optFns ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) { + return c.client.GetInstanceIdentityDocument(ctx, params, optFns...) } -func (c *ec2MetadataClientImpl) Region() (string, error) { - return c.client.Region() +// GetRegion returns the AWS Region the instance is running in +func (c *ec2MetadataClientImpl) GetRegion(ctx context.Context, params *imds.GetRegionInput, optFns ...func(*imds.Options)) (*imds.GetRegionOutput, error) { + return c.client.GetRegion(ctx, params, optFns...) } diff --git a/pkg/ec2metadatawrapper/ec2metadatawrapper_test.go b/pkg/ec2metadatawrapper/ec2metadatawrapper_test.go index b88f8555f0..81c390ac4c 100644 --- a/pkg/ec2metadatawrapper/ec2metadatawrapper_test.go +++ b/pkg/ec2metadatawrapper/ec2metadatawrapper_test.go @@ -1,11 +1,12 @@ package ec2metadatawrapper import ( + "context" "testing" mockec2metadatawrapper "github.com/aws/amazon-vpc-cni-k8s/pkg/ec2metadatawrapper/mocks" - "github.com/aws/aws-sdk-go/aws/ec2metadata" + ec2metadata "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" @@ -16,7 +17,7 @@ const ( iidRegion = "us-east-1" ) -var testInstanceIdentityDoc = ec2metadata.EC2InstanceIdentityDocument{ +var testInstanceIdentityDoc = ec2metadata.InstanceIdentityDocument{ Version: "2010-08-31", Region: "us-east-1", InstanceID: "i-01234567", @@ -30,9 +31,13 @@ func TestGetInstanceIdentityDocHappyPath(t *testing.T) { mockGetter := mockec2metadatawrapper.NewMockHTTPClient(ctrl) testClient := NewMetadataService(mockGetter) - mockGetter.EXPECT().GetInstanceIdentityDocument().Return(testInstanceIdentityDoc, nil) + mockGetter.EXPECT().GetInstanceIdentityDocument(gomock.Any(), gomock.Any()).Return(&ec2metadata.GetInstanceIdentityDocumentOutput{ + InstanceIdentityDocument: testInstanceIdentityDoc, + }, nil) - doc, err := testClient.GetInstanceIdentityDocument() + ctx := context.Background() + + doc, err := testClient.GetInstanceIdentityDocument(ctx, &ec2metadata.GetInstanceIdentityDocumentInput{}) assert.NoError(t, err) assert.Equal(t, iidRegion, doc.Region) } @@ -44,9 +49,9 @@ func TestGetInstanceIdentityDocError(t *testing.T) { mockGetter := mockec2metadatawrapper.NewMockHTTPClient(ctrl) testClient := NewMetadataService(mockGetter) - mockGetter.EXPECT().GetInstanceIdentityDocument().Return(ec2metadata.EC2InstanceIdentityDocument{}, errors.New("test error")) - - doc, err := testClient.GetInstanceIdentityDocument() + mockGetter.EXPECT().GetInstanceIdentityDocument(gomock.Any(), gomock.Any()).Return(&ec2metadata.GetInstanceIdentityDocumentOutput{}, errors.New("test error")) + ctx := context.Background() + doc, err := testClient.GetInstanceIdentityDocument(ctx, &ec2metadata.GetInstanceIdentityDocumentInput{}) assert.Error(t, err) assert.Empty(t, doc.Region) } @@ -55,26 +60,27 @@ func TestGetRegionHappyPath(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - mockGetter := mockec2metadatawrapper.NewMockHTTPClient(ctrl) + mockGetter := mockec2metadatawrapper.NewMockEC2MetadataClient(ctrl) testClient := NewMetadataService(mockGetter) - mockGetter.EXPECT().Region().Return(iidRegion, nil) + expectedRegion := "us-west-2" + mockGetter.EXPECT().GetRegion(gomock.Any(), gomock.Any()).Return(&ec2metadata.GetRegionOutput{Region: expectedRegion}, nil) - region, err := testClient.Region() + region, err := testClient.GetRegion(context.Background(), &ec2metadata.GetRegionInput{}) assert.NoError(t, err) - assert.Equal(t, iidRegion, region) + assert.Equal(t, expectedRegion, region.Region) } func TestGetRegionErr(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - mockGetter := mockec2metadatawrapper.NewMockHTTPClient(ctrl) + mockGetter := mockec2metadatawrapper.NewMockEC2MetadataClient(ctrl) testClient := NewMetadataService(mockGetter) - mockGetter.EXPECT().Region().Return("", errors.New("test error")) + mockGetter.EXPECT().GetRegion(gomock.Any(), gomock.Any()).Return(nil, errors.New("test error")) - region, err := testClient.Region() + region, err := testClient.GetRegion(context.Background(), &ec2metadata.GetRegionInput{}) assert.Error(t, err) assert.Empty(t, region) } diff --git a/pkg/ec2metadatawrapper/mocks/ec2metadatawrapper_mocks.go b/pkg/ec2metadatawrapper/mocks/ec2metadatawrapper_mocks.go index 5126131b25..c26e0d44fa 100644 --- a/pkg/ec2metadatawrapper/mocks/ec2metadatawrapper_mocks.go +++ b/pkg/ec2metadatawrapper/mocks/ec2metadatawrapper_mocks.go @@ -19,9 +19,10 @@ package mock_ec2metadatawrapper import ( + context "context" reflect "reflect" - ec2metadata "github.com/aws/aws-sdk-go/aws/ec2metadata" + imds "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" gomock "github.com/golang/mock/gomock" ) @@ -49,33 +50,43 @@ func (m *MockHTTPClient) EXPECT() *MockHTTPClientMockRecorder { } // GetInstanceIdentityDocument mocks base method. -func (m *MockHTTPClient) GetInstanceIdentityDocument() (ec2metadata.EC2InstanceIdentityDocument, error) { +func (m *MockHTTPClient) GetInstanceIdentityDocument(arg0 context.Context, arg1 *imds.GetInstanceIdentityDocumentInput, arg2 ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetInstanceIdentityDocument") - ret0, _ := ret[0].(ec2metadata.EC2InstanceIdentityDocument) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetInstanceIdentityDocument", varargs...) + ret0, _ := ret[0].(*imds.GetInstanceIdentityDocumentOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // GetInstanceIdentityDocument indicates an expected call of GetInstanceIdentityDocument. -func (mr *MockHTTPClientMockRecorder) GetInstanceIdentityDocument() *gomock.Call { +func (mr *MockHTTPClientMockRecorder) GetInstanceIdentityDocument(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInstanceIdentityDocument", reflect.TypeOf((*MockHTTPClient)(nil).GetInstanceIdentityDocument)) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInstanceIdentityDocument", reflect.TypeOf((*MockHTTPClient)(nil).GetInstanceIdentityDocument), varargs...) } -// Region mocks base method. -func (m *MockHTTPClient) Region() (string, error) { +// GetRegion mocks base method. +func (m *MockHTTPClient) GetRegion(arg0 context.Context, arg1 *imds.GetRegionInput, arg2 ...func(*imds.Options)) (*imds.GetRegionOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Region") - ret0, _ := ret[0].(string) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetRegion", varargs...) + ret0, _ := ret[0].(*imds.GetRegionOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// Region indicates an expected call of Region. -func (mr *MockHTTPClientMockRecorder) Region() *gomock.Call { +// GetRegion indicates an expected call of GetRegion. +func (mr *MockHTTPClientMockRecorder) GetRegion(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Region", reflect.TypeOf((*MockHTTPClient)(nil).Region)) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRegion", reflect.TypeOf((*MockHTTPClient)(nil).GetRegion), varargs...) } // MockEC2MetadataClient is a mock of EC2MetadataClient interface. @@ -102,31 +113,41 @@ func (m *MockEC2MetadataClient) EXPECT() *MockEC2MetadataClientMockRecorder { } // GetInstanceIdentityDocument mocks base method. -func (m *MockEC2MetadataClient) GetInstanceIdentityDocument() (ec2metadata.EC2InstanceIdentityDocument, error) { +func (m *MockEC2MetadataClient) GetInstanceIdentityDocument(arg0 context.Context, arg1 *imds.GetInstanceIdentityDocumentInput, arg2 ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetInstanceIdentityDocument") - ret0, _ := ret[0].(ec2metadata.EC2InstanceIdentityDocument) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetInstanceIdentityDocument", varargs...) + ret0, _ := ret[0].(*imds.GetInstanceIdentityDocumentOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // GetInstanceIdentityDocument indicates an expected call of GetInstanceIdentityDocument. -func (mr *MockEC2MetadataClientMockRecorder) GetInstanceIdentityDocument() *gomock.Call { +func (mr *MockEC2MetadataClientMockRecorder) GetInstanceIdentityDocument(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInstanceIdentityDocument", reflect.TypeOf((*MockEC2MetadataClient)(nil).GetInstanceIdentityDocument)) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInstanceIdentityDocument", reflect.TypeOf((*MockEC2MetadataClient)(nil).GetInstanceIdentityDocument), varargs...) } -// Region mocks base method. -func (m *MockEC2MetadataClient) Region() (string, error) { +// GetRegion mocks base method. +func (m *MockEC2MetadataClient) GetRegion(arg0 context.Context, arg1 *imds.GetRegionInput, arg2 ...func(*imds.Options)) (*imds.GetRegionOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Region") - ret0, _ := ret[0].(string) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetRegion", varargs...) + ret0, _ := ret[0].(*imds.GetRegionOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// Region indicates an expected call of Region. -func (mr *MockEC2MetadataClientMockRecorder) Region() *gomock.Call { +// GetRegion indicates an expected call of GetRegion. +func (mr *MockEC2MetadataClientMockRecorder) GetRegion(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Region", reflect.TypeOf((*MockEC2MetadataClient)(nil).Region)) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRegion", reflect.TypeOf((*MockEC2MetadataClient)(nil).GetRegion), varargs...) } diff --git a/pkg/ec2wrapper/client.go b/pkg/ec2wrapper/client.go index 09242ab08f..eca2c897fa 100644 --- a/pkg/ec2wrapper/client.go +++ b/pkg/ec2wrapper/client.go @@ -14,32 +14,31 @@ package ec2wrapper import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - ec2svc "github.com/aws/aws-sdk-go/service/ec2" + "context" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" ) // EC2 is the EC2 wrapper interface type EC2 interface { - CreateNetworkInterfaceWithContext(ctx aws.Context, input *ec2svc.CreateNetworkInterfaceInput, opts ...request.Option) (*ec2svc.CreateNetworkInterfaceOutput, error) - DescribeInstancesWithContext(ctx aws.Context, input *ec2svc.DescribeInstancesInput, opts ...request.Option) (*ec2svc.DescribeInstancesOutput, error) - DescribeInstanceTypesWithContext(ctx aws.Context, input *ec2svc.DescribeInstanceTypesInput, opts ...request.Option) (*ec2svc.DescribeInstanceTypesOutput, error) - AttachNetworkInterfaceWithContext(ctx aws.Context, input *ec2svc.AttachNetworkInterfaceInput, opts ...request.Option) (*ec2svc.AttachNetworkInterfaceOutput, error) - DeleteNetworkInterfaceWithContext(ctx aws.Context, input *ec2svc.DeleteNetworkInterfaceInput, opts ...request.Option) (*ec2svc.DeleteNetworkInterfaceOutput, error) - DetachNetworkInterfaceWithContext(ctx aws.Context, input *ec2svc.DetachNetworkInterfaceInput, opts ...request.Option) (*ec2svc.DetachNetworkInterfaceOutput, error) - AssignPrivateIpAddressesWithContext(ctx aws.Context, input *ec2svc.AssignPrivateIpAddressesInput, opts ...request.Option) (*ec2svc.AssignPrivateIpAddressesOutput, error) - UnassignPrivateIpAddressesWithContext(ctx aws.Context, input *ec2svc.UnassignPrivateIpAddressesInput, opts ...request.Option) (*ec2svc.UnassignPrivateIpAddressesOutput, error) - AssignIpv6AddressesWithContext(ctx aws.Context, input *ec2svc.AssignIpv6AddressesInput, opts ...request.Option) (*ec2svc.AssignIpv6AddressesOutput, error) - UnassignIpv6AddressesWithContext(ctx aws.Context, input *ec2svc.UnassignIpv6AddressesInput, opts ...request.Option) (*ec2svc.UnassignIpv6AddressesOutput, error) - DescribeNetworkInterfacesWithContext(ctx aws.Context, input *ec2svc.DescribeNetworkInterfacesInput, opts ...request.Option) (*ec2svc.DescribeNetworkInterfacesOutput, error) - ModifyNetworkInterfaceAttributeWithContext(ctx aws.Context, input *ec2svc.ModifyNetworkInterfaceAttributeInput, opts ...request.Option) (*ec2svc.ModifyNetworkInterfaceAttributeOutput, error) - CreateTagsWithContext(ctx aws.Context, input *ec2svc.CreateTagsInput, opts ...request.Option) (*ec2svc.CreateTagsOutput, error) - DescribeNetworkInterfacesPagesWithContext(ctx aws.Context, input *ec2svc.DescribeNetworkInterfacesInput, fn func(*ec2svc.DescribeNetworkInterfacesOutput, bool) bool, opts ...request.Option) error - DescribeSubnetsWithContext(ctx aws.Context, input *ec2svc.DescribeSubnetsInput, opts ...request.Option) (*ec2svc.DescribeSubnetsOutput, error) + CreateNetworkInterface(ctx context.Context, input *ec2.CreateNetworkInterfaceInput, opts ...func(*ec2.Options)) (*ec2.CreateNetworkInterfaceOutput, error) + DescribeInstances(ctx context.Context, input *ec2.DescribeInstancesInput, opts ...func(*ec2.Options)) (*ec2.DescribeInstancesOutput, error) + DescribeInstanceTypes(ctx context.Context, input *ec2.DescribeInstanceTypesInput, opts ...func(*ec2.Options)) (*ec2.DescribeInstanceTypesOutput, error) + AttachNetworkInterface(ctx context.Context, input *ec2.AttachNetworkInterfaceInput, opts ...func(*ec2.Options)) (*ec2.AttachNetworkInterfaceOutput, error) + DeleteNetworkInterface(ctx context.Context, input *ec2.DeleteNetworkInterfaceInput, opts ...func(*ec2.Options)) (*ec2.DeleteNetworkInterfaceOutput, error) + DetachNetworkInterface(ctx context.Context, input *ec2.DetachNetworkInterfaceInput, opts ...func(*ec2.Options)) (*ec2.DetachNetworkInterfaceOutput, error) + AssignPrivateIpAddresses(ctx context.Context, input *ec2.AssignPrivateIpAddressesInput, opts ...func(*ec2.Options)) (*ec2.AssignPrivateIpAddressesOutput, error) + UnassignPrivateIpAddresses(ctx context.Context, input *ec2.UnassignPrivateIpAddressesInput, opts ...func(*ec2.Options)) (*ec2.UnassignPrivateIpAddressesOutput, error) + AssignIpv6Addresses(ctx context.Context, input *ec2.AssignIpv6AddressesInput, opts ...func(*ec2.Options)) (*ec2.AssignIpv6AddressesOutput, error) + UnassignIpv6Addresses(ctx context.Context, input *ec2.UnassignIpv6AddressesInput, opts ...func(*ec2.Options)) (*ec2.UnassignIpv6AddressesOutput, error) + DescribeNetworkInterfaces(ctx context.Context, input *ec2.DescribeNetworkInterfacesInput, opts ...func(*ec2.Options)) (*ec2.DescribeNetworkInterfacesOutput, error) + ModifyNetworkInterfaceAttribute(ctx context.Context, input *ec2.ModifyNetworkInterfaceAttributeInput, opts ...func(*ec2.Options)) (*ec2.ModifyNetworkInterfaceAttributeOutput, error) + CreateTags(ctx context.Context, input *ec2.CreateTagsInput, opts ...func(*ec2.Options)) (*ec2.CreateTagsOutput, error) + DescribeSubnets(ctx context.Context, input *ec2.DescribeSubnetsInput, opts ...func(*ec2.Options)) (*ec2.DescribeSubnetsOutput, error) } // New creates a new EC2 wrapper -func New(sess *session.Session) EC2 { - return ec2svc.New(sess) +func New(cfg aws.Config) *ec2.Client { + return ec2.NewFromConfig(cfg) } diff --git a/pkg/ec2wrapper/ec2wrapper.go b/pkg/ec2wrapper/ec2wrapper.go index 4d736dece9..6b1be12d56 100644 --- a/pkg/ec2wrapper/ec2wrapper.go +++ b/pkg/ec2wrapper/ec2wrapper.go @@ -2,13 +2,15 @@ package ec2wrapper import ( - "github.com/aws/amazon-vpc-cni-k8s/pkg/awsutils/awssession" + "context" + "github.com/aws/amazon-vpc-cni-k8s/pkg/ec2metadatawrapper" "github.com/aws/amazon-vpc-cni-k8s/pkg/utils/logger" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/ec2metadata" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + ec2metadata "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" + "github.com/aws/aws-sdk-go-v2/service/ec2" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/pkg/errors" ) @@ -23,50 +25,56 @@ var log = logger.Get() // EC2Wrapper is used to wrap around EC2 service APIs to obtain ClusterID from // the ec2 instance tags type EC2Wrapper struct { - ec2ServiceClient ec2iface.EC2API - instanceIdentityDocument ec2metadata.EC2InstanceIdentityDocument + ec2ServiceClient ec2.DescribeTagsAPIClient + instanceIdentityDocument ec2metadata.InstanceIdentityDocument } // NewMetricsClient returns an instance of the EC2 wrapper func NewMetricsClient() (*EC2Wrapper, error) { - sess := awssession.New() - ec2MetadataClient := ec2metadatawrapper.New(sess) + ctx := context.TODO() + ec2MetadataClient, err := ec2metadatawrapper.New(ctx) + if err != nil { + return &EC2Wrapper{}, err + } - instanceIdentityDocument, err := ec2MetadataClient.GetInstanceIdentityDocument() + instanceIdentityDocumentOutput, err := ec2MetadataClient.GetInstanceIdentityDocument(ctx, &ec2metadata.GetInstanceIdentityDocumentInput{}) if err != nil { return &EC2Wrapper{}, err } - awsCfg := aws.NewConfig().WithRegion(instanceIdentityDocument.Region) - sess = sess.Copy(awsCfg) - ec2ServiceClient := ec2.New(sess) + awsCfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(instanceIdentityDocumentOutput.Region)) + if err != nil { + return &EC2Wrapper{}, err + } + ec2ServiceClient := ec2.NewFromConfig(awsCfg) return &EC2Wrapper{ ec2ServiceClient: ec2ServiceClient, - instanceIdentityDocument: instanceIdentityDocument, + instanceIdentityDocument: instanceIdentityDocumentOutput.InstanceIdentityDocument, }, nil } // GetClusterTag is used to retrieve a tag from the ec2 instance func (e *EC2Wrapper) GetClusterTag(tagKey string) (string, error) { + ctx := context.TODO() input := ec2.DescribeTagsInput{ - Filters: []*ec2.Filter{ + Filters: []ec2types.Filter{ { Name: aws.String(resourceID), - Values: []*string{ - aws.String(e.instanceIdentityDocument.InstanceID), + Values: []string{ + e.instanceIdentityDocument.InstanceID, }, }, { Name: aws.String(resourceKey), - Values: []*string{ - aws.String(tagKey), + Values: []string{ + tagKey, }, }, }, } log.Infof("Calling DescribeTags with key %s", tagKey) - results, err := e.ec2ServiceClient.DescribeTags(&input) + results, err := e.ec2ServiceClient.DescribeTags(ctx, &input) if err != nil { return "", errors.Wrap(err, "GetClusterTag: Unable to obtain EC2 instance tags") } @@ -75,5 +83,5 @@ func (e *EC2Wrapper) GetClusterTag(tagKey string) (string, error) { return "", errors.Errorf("GetClusterTag: No tag matching key: %s", tagKey) } - return aws.StringValue(results.Tags[0].Value), nil + return aws.ToString(results.Tags[0].Value), nil } diff --git a/pkg/ec2wrapper/ec2wrapper_test.go b/pkg/ec2wrapper/ec2wrapper_test.go index 6ffc43c3c9..6817fec954 100644 --- a/pkg/ec2wrapper/ec2wrapper_test.go +++ b/pkg/ec2wrapper/ec2wrapper_test.go @@ -1,18 +1,19 @@ package ec2wrapper import ( + "context" "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/ec2metadata" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/aws/aws-sdk-go-v2/aws" + ec2metadata "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" + "github.com/aws/aws-sdk-go-v2/service/ec2" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) -var testInstanceIdentityDocument = ec2metadata.EC2InstanceIdentityDocument{ +var testInstanceIdentityDocument = ec2metadata.InstanceIdentityDocument{ PrivateIP: "172.1.1.1", AvailabilityZone: "us-east-1a", Version: "2010-08-31", @@ -29,7 +30,7 @@ var testInstanceIdentityDocument = ec2metadata.EC2InstanceIdentityDocument{ func TestGetClusterID(t *testing.T) { mockEC2ServiceClient := mockEC2ServiceClient{ tags: &ec2.DescribeTagsOutput{ - Tags: []*ec2.TagDescription{ + Tags: []ec2types.TagDescription{ { Value: aws.String("TEST_CLUSTER_ID"), }, @@ -65,7 +66,7 @@ func TestGetClusterIDWithError(t *testing.T) { func TestGetClusterIDWithInsufficientTags(t *testing.T) { mockEC2ServiceClient := mockEC2ServiceClient{ tags: &ec2.DescribeTagsOutput{ - Tags: []*ec2.TagDescription{}, + Tags: []ec2types.TagDescription{}, }, } @@ -80,12 +81,11 @@ func TestGetClusterIDWithInsufficientTags(t *testing.T) { } type mockEC2ServiceClient struct { - ec2iface.EC2API + ec2.DescribeInstancesAPIClient tags *ec2.DescribeTagsOutput tagsErr error } -func (f mockEC2ServiceClient) DescribeTags(input *ec2.DescribeTagsInput) (*ec2.DescribeTagsOutput, error) { - return f.tags, f.tagsErr - +func (m mockEC2ServiceClient) DescribeTags(ctx context.Context, input *ec2.DescribeTagsInput, f ...func(*ec2.Options)) (*ec2.DescribeTagsOutput, error) { + return m.tags, m.tagsErr } diff --git a/pkg/ec2wrapper/mocks/ec2wrapper_mocks.go b/pkg/ec2wrapper/mocks/ec2wrapper_mocks.go index 53446727f5..cf8cb72824 100644 --- a/pkg/ec2wrapper/mocks/ec2wrapper_mocks.go +++ b/pkg/ec2wrapper/mocks/ec2wrapper_mocks.go @@ -22,8 +22,7 @@ import ( context "context" reflect "reflect" - request "github.com/aws/aws-sdk-go/aws/request" - ec2 "github.com/aws/aws-sdk-go/service/ec2" + ec2 "github.com/aws/aws-sdk-go-v2/service/ec2" gomock "github.com/golang/mock/gomock" ) @@ -50,301 +49,282 @@ func (m *MockEC2) EXPECT() *MockEC2MockRecorder { return m.recorder } -// AssignIpv6AddressesWithContext mocks base method. -func (m *MockEC2) AssignIpv6AddressesWithContext(arg0 context.Context, arg1 *ec2.AssignIpv6AddressesInput, arg2 ...request.Option) (*ec2.AssignIpv6AddressesOutput, error) { +// AssignIpv6Addresses mocks base method. +func (m *MockEC2) AssignIpv6Addresses(arg0 context.Context, arg1 *ec2.AssignIpv6AddressesInput, arg2 ...func(*ec2.Options)) (*ec2.AssignIpv6AddressesOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "AssignIpv6AddressesWithContext", varargs...) + ret := m.ctrl.Call(m, "AssignIpv6Addresses", varargs...) ret0, _ := ret[0].(*ec2.AssignIpv6AddressesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// AssignIpv6AddressesWithContext indicates an expected call of AssignIpv6AddressesWithContext. -func (mr *MockEC2MockRecorder) AssignIpv6AddressesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// AssignIpv6Addresses indicates an expected call of AssignIpv6Addresses. +func (mr *MockEC2MockRecorder) AssignIpv6Addresses(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssignIpv6AddressesWithContext", reflect.TypeOf((*MockEC2)(nil).AssignIpv6AddressesWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssignIpv6Addresses", reflect.TypeOf((*MockEC2)(nil).AssignIpv6Addresses), varargs...) } -// AssignPrivateIpAddressesWithContext mocks base method. -func (m *MockEC2) AssignPrivateIpAddressesWithContext(arg0 context.Context, arg1 *ec2.AssignPrivateIpAddressesInput, arg2 ...request.Option) (*ec2.AssignPrivateIpAddressesOutput, error) { +// AssignPrivateIpAddresses mocks base method. +func (m *MockEC2) AssignPrivateIpAddresses(arg0 context.Context, arg1 *ec2.AssignPrivateIpAddressesInput, arg2 ...func(*ec2.Options)) (*ec2.AssignPrivateIpAddressesOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "AssignPrivateIpAddressesWithContext", varargs...) + ret := m.ctrl.Call(m, "AssignPrivateIpAddresses", varargs...) ret0, _ := ret[0].(*ec2.AssignPrivateIpAddressesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// AssignPrivateIpAddressesWithContext indicates an expected call of AssignPrivateIpAddressesWithContext. -func (mr *MockEC2MockRecorder) AssignPrivateIpAddressesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// AssignPrivateIpAddresses indicates an expected call of AssignPrivateIpAddresses. +func (mr *MockEC2MockRecorder) AssignPrivateIpAddresses(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssignPrivateIpAddressesWithContext", reflect.TypeOf((*MockEC2)(nil).AssignPrivateIpAddressesWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssignPrivateIpAddresses", reflect.TypeOf((*MockEC2)(nil).AssignPrivateIpAddresses), varargs...) } -// AttachNetworkInterfaceWithContext mocks base method. -func (m *MockEC2) AttachNetworkInterfaceWithContext(arg0 context.Context, arg1 *ec2.AttachNetworkInterfaceInput, arg2 ...request.Option) (*ec2.AttachNetworkInterfaceOutput, error) { +// AttachNetworkInterface mocks base method. +func (m *MockEC2) AttachNetworkInterface(arg0 context.Context, arg1 *ec2.AttachNetworkInterfaceInput, arg2 ...func(*ec2.Options)) (*ec2.AttachNetworkInterfaceOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "AttachNetworkInterfaceWithContext", varargs...) + ret := m.ctrl.Call(m, "AttachNetworkInterface", varargs...) ret0, _ := ret[0].(*ec2.AttachNetworkInterfaceOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// AttachNetworkInterfaceWithContext indicates an expected call of AttachNetworkInterfaceWithContext. -func (mr *MockEC2MockRecorder) AttachNetworkInterfaceWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// AttachNetworkInterface indicates an expected call of AttachNetworkInterface. +func (mr *MockEC2MockRecorder) AttachNetworkInterface(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AttachNetworkInterfaceWithContext", reflect.TypeOf((*MockEC2)(nil).AttachNetworkInterfaceWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AttachNetworkInterface", reflect.TypeOf((*MockEC2)(nil).AttachNetworkInterface), varargs...) } -// CreateNetworkInterfaceWithContext mocks base method. -func (m *MockEC2) CreateNetworkInterfaceWithContext(arg0 context.Context, arg1 *ec2.CreateNetworkInterfaceInput, arg2 ...request.Option) (*ec2.CreateNetworkInterfaceOutput, error) { +// CreateNetworkInterface mocks base method. +func (m *MockEC2) CreateNetworkInterface(arg0 context.Context, arg1 *ec2.CreateNetworkInterfaceInput, arg2 ...func(*ec2.Options)) (*ec2.CreateNetworkInterfaceOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "CreateNetworkInterfaceWithContext", varargs...) + ret := m.ctrl.Call(m, "CreateNetworkInterface", varargs...) ret0, _ := ret[0].(*ec2.CreateNetworkInterfaceOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// CreateNetworkInterfaceWithContext indicates an expected call of CreateNetworkInterfaceWithContext. -func (mr *MockEC2MockRecorder) CreateNetworkInterfaceWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// CreateNetworkInterface indicates an expected call of CreateNetworkInterface. +func (mr *MockEC2MockRecorder) CreateNetworkInterface(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNetworkInterfaceWithContext", reflect.TypeOf((*MockEC2)(nil).CreateNetworkInterfaceWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNetworkInterface", reflect.TypeOf((*MockEC2)(nil).CreateNetworkInterface), varargs...) } -// CreateTagsWithContext mocks base method. -func (m *MockEC2) CreateTagsWithContext(arg0 context.Context, arg1 *ec2.CreateTagsInput, arg2 ...request.Option) (*ec2.CreateTagsOutput, error) { +// CreateTags mocks base method. +func (m *MockEC2) CreateTags(arg0 context.Context, arg1 *ec2.CreateTagsInput, arg2 ...func(*ec2.Options)) (*ec2.CreateTagsOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "CreateTagsWithContext", varargs...) + ret := m.ctrl.Call(m, "CreateTags", varargs...) ret0, _ := ret[0].(*ec2.CreateTagsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// CreateTagsWithContext indicates an expected call of CreateTagsWithContext. -func (mr *MockEC2MockRecorder) CreateTagsWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// CreateTags indicates an expected call of CreateTags. +func (mr *MockEC2MockRecorder) CreateTags(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTagsWithContext", reflect.TypeOf((*MockEC2)(nil).CreateTagsWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTags", reflect.TypeOf((*MockEC2)(nil).CreateTags), varargs...) } -// DeleteNetworkInterfaceWithContext mocks base method. -func (m *MockEC2) DeleteNetworkInterfaceWithContext(arg0 context.Context, arg1 *ec2.DeleteNetworkInterfaceInput, arg2 ...request.Option) (*ec2.DeleteNetworkInterfaceOutput, error) { +// DeleteNetworkInterface mocks base method. +func (m *MockEC2) DeleteNetworkInterface(arg0 context.Context, arg1 *ec2.DeleteNetworkInterfaceInput, arg2 ...func(*ec2.Options)) (*ec2.DeleteNetworkInterfaceOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "DeleteNetworkInterfaceWithContext", varargs...) + ret := m.ctrl.Call(m, "DeleteNetworkInterface", varargs...) ret0, _ := ret[0].(*ec2.DeleteNetworkInterfaceOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// DeleteNetworkInterfaceWithContext indicates an expected call of DeleteNetworkInterfaceWithContext. -func (mr *MockEC2MockRecorder) DeleteNetworkInterfaceWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// DeleteNetworkInterface indicates an expected call of DeleteNetworkInterface. +func (mr *MockEC2MockRecorder) DeleteNetworkInterface(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteNetworkInterfaceWithContext", reflect.TypeOf((*MockEC2)(nil).DeleteNetworkInterfaceWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteNetworkInterface", reflect.TypeOf((*MockEC2)(nil).DeleteNetworkInterface), varargs...) } -// DescribeInstanceTypesWithContext mocks base method. -func (m *MockEC2) DescribeInstanceTypesWithContext(arg0 context.Context, arg1 *ec2.DescribeInstanceTypesInput, arg2 ...request.Option) (*ec2.DescribeInstanceTypesOutput, error) { +// DescribeInstanceTypes mocks base method. +func (m *MockEC2) DescribeInstanceTypes(arg0 context.Context, arg1 *ec2.DescribeInstanceTypesInput, arg2 ...func(*ec2.Options)) (*ec2.DescribeInstanceTypesOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "DescribeInstanceTypesWithContext", varargs...) + ret := m.ctrl.Call(m, "DescribeInstanceTypes", varargs...) ret0, _ := ret[0].(*ec2.DescribeInstanceTypesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// DescribeInstanceTypesWithContext indicates an expected call of DescribeInstanceTypesWithContext. -func (mr *MockEC2MockRecorder) DescribeInstanceTypesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// DescribeInstanceTypes indicates an expected call of DescribeInstanceTypes. +func (mr *MockEC2MockRecorder) DescribeInstanceTypes(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeInstanceTypesWithContext", reflect.TypeOf((*MockEC2)(nil).DescribeInstanceTypesWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeInstanceTypes", reflect.TypeOf((*MockEC2)(nil).DescribeInstanceTypes), varargs...) } -// DescribeInstancesWithContext mocks base method. -func (m *MockEC2) DescribeInstancesWithContext(arg0 context.Context, arg1 *ec2.DescribeInstancesInput, arg2 ...request.Option) (*ec2.DescribeInstancesOutput, error) { +// DescribeInstances mocks base method. +func (m *MockEC2) DescribeInstances(arg0 context.Context, arg1 *ec2.DescribeInstancesInput, arg2 ...func(*ec2.Options)) (*ec2.DescribeInstancesOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "DescribeInstancesWithContext", varargs...) + ret := m.ctrl.Call(m, "DescribeInstances", varargs...) ret0, _ := ret[0].(*ec2.DescribeInstancesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// DescribeInstancesWithContext indicates an expected call of DescribeInstancesWithContext. -func (mr *MockEC2MockRecorder) DescribeInstancesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// DescribeInstances indicates an expected call of DescribeInstances. +func (mr *MockEC2MockRecorder) DescribeInstances(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeInstancesWithContext", reflect.TypeOf((*MockEC2)(nil).DescribeInstancesWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeInstances", reflect.TypeOf((*MockEC2)(nil).DescribeInstances), varargs...) } -// DescribeNetworkInterfacesPagesWithContext mocks base method. -func (m *MockEC2) DescribeNetworkInterfacesPagesWithContext(arg0 context.Context, arg1 *ec2.DescribeNetworkInterfacesInput, arg2 func(*ec2.DescribeNetworkInterfacesOutput, bool) bool, arg3 ...request.Option) error { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1, arg2} - for _, a := range arg3 { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeNetworkInterfacesPagesWithContext", varargs...) - ret0, _ := ret[0].(error) - return ret0 -} - -// DescribeNetworkInterfacesPagesWithContext indicates an expected call of DescribeNetworkInterfacesPagesWithContext. -func (mr *MockEC2MockRecorder) DescribeNetworkInterfacesPagesWithContext(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1, arg2}, arg3...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeNetworkInterfacesPagesWithContext", reflect.TypeOf((*MockEC2)(nil).DescribeNetworkInterfacesPagesWithContext), varargs...) -} - -// DescribeNetworkInterfacesWithContext mocks base method. -func (m *MockEC2) DescribeNetworkInterfacesWithContext(arg0 context.Context, arg1 *ec2.DescribeNetworkInterfacesInput, arg2 ...request.Option) (*ec2.DescribeNetworkInterfacesOutput, error) { +// DescribeNetworkInterfaces mocks base method. +func (m *MockEC2) DescribeNetworkInterfaces(arg0 context.Context, arg1 *ec2.DescribeNetworkInterfacesInput, arg2 ...func(*ec2.Options)) (*ec2.DescribeNetworkInterfacesOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "DescribeNetworkInterfacesWithContext", varargs...) + ret := m.ctrl.Call(m, "DescribeNetworkInterfaces", varargs...) ret0, _ := ret[0].(*ec2.DescribeNetworkInterfacesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// DescribeNetworkInterfacesWithContext indicates an expected call of DescribeNetworkInterfacesWithContext. -func (mr *MockEC2MockRecorder) DescribeNetworkInterfacesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// DescribeNetworkInterfaces indicates an expected call of DescribeNetworkInterfaces. +func (mr *MockEC2MockRecorder) DescribeNetworkInterfaces(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeNetworkInterfacesWithContext", reflect.TypeOf((*MockEC2)(nil).DescribeNetworkInterfacesWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeNetworkInterfaces", reflect.TypeOf((*MockEC2)(nil).DescribeNetworkInterfaces), varargs...) } -// DescribeSubnetsWithContext mocks base method. -func (m *MockEC2) DescribeSubnetsWithContext(arg0 context.Context, arg1 *ec2.DescribeSubnetsInput, arg2 ...request.Option) (*ec2.DescribeSubnetsOutput, error) { +// DescribeSubnets mocks base method. +func (m *MockEC2) DescribeSubnets(arg0 context.Context, arg1 *ec2.DescribeSubnetsInput, arg2 ...func(*ec2.Options)) (*ec2.DescribeSubnetsOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "DescribeSubnetsWithContext", varargs...) + ret := m.ctrl.Call(m, "DescribeSubnets", varargs...) ret0, _ := ret[0].(*ec2.DescribeSubnetsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// DescribeSubnetsWithContext indicates an expected call of DescribeSubnetsWithContext. -func (mr *MockEC2MockRecorder) DescribeSubnetsWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// DescribeSubnets indicates an expected call of DescribeSubnets. +func (mr *MockEC2MockRecorder) DescribeSubnets(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeSubnetsWithContext", reflect.TypeOf((*MockEC2)(nil).DescribeSubnetsWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeSubnets", reflect.TypeOf((*MockEC2)(nil).DescribeSubnets), varargs...) } -// DetachNetworkInterfaceWithContext mocks base method. -func (m *MockEC2) DetachNetworkInterfaceWithContext(arg0 context.Context, arg1 *ec2.DetachNetworkInterfaceInput, arg2 ...request.Option) (*ec2.DetachNetworkInterfaceOutput, error) { +// DetachNetworkInterface mocks base method. +func (m *MockEC2) DetachNetworkInterface(arg0 context.Context, arg1 *ec2.DetachNetworkInterfaceInput, arg2 ...func(*ec2.Options)) (*ec2.DetachNetworkInterfaceOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "DetachNetworkInterfaceWithContext", varargs...) + ret := m.ctrl.Call(m, "DetachNetworkInterface", varargs...) ret0, _ := ret[0].(*ec2.DetachNetworkInterfaceOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// DetachNetworkInterfaceWithContext indicates an expected call of DetachNetworkInterfaceWithContext. -func (mr *MockEC2MockRecorder) DetachNetworkInterfaceWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// DetachNetworkInterface indicates an expected call of DetachNetworkInterface. +func (mr *MockEC2MockRecorder) DetachNetworkInterface(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DetachNetworkInterfaceWithContext", reflect.TypeOf((*MockEC2)(nil).DetachNetworkInterfaceWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DetachNetworkInterface", reflect.TypeOf((*MockEC2)(nil).DetachNetworkInterface), varargs...) } -// ModifyNetworkInterfaceAttributeWithContext mocks base method. -func (m *MockEC2) ModifyNetworkInterfaceAttributeWithContext(arg0 context.Context, arg1 *ec2.ModifyNetworkInterfaceAttributeInput, arg2 ...request.Option) (*ec2.ModifyNetworkInterfaceAttributeOutput, error) { +// ModifyNetworkInterfaceAttribute mocks base method. +func (m *MockEC2) ModifyNetworkInterfaceAttribute(arg0 context.Context, arg1 *ec2.ModifyNetworkInterfaceAttributeInput, arg2 ...func(*ec2.Options)) (*ec2.ModifyNetworkInterfaceAttributeOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "ModifyNetworkInterfaceAttributeWithContext", varargs...) + ret := m.ctrl.Call(m, "ModifyNetworkInterfaceAttribute", varargs...) ret0, _ := ret[0].(*ec2.ModifyNetworkInterfaceAttributeOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// ModifyNetworkInterfaceAttributeWithContext indicates an expected call of ModifyNetworkInterfaceAttributeWithContext. -func (mr *MockEC2MockRecorder) ModifyNetworkInterfaceAttributeWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// ModifyNetworkInterfaceAttribute indicates an expected call of ModifyNetworkInterfaceAttribute. +func (mr *MockEC2MockRecorder) ModifyNetworkInterfaceAttribute(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyNetworkInterfaceAttributeWithContext", reflect.TypeOf((*MockEC2)(nil).ModifyNetworkInterfaceAttributeWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyNetworkInterfaceAttribute", reflect.TypeOf((*MockEC2)(nil).ModifyNetworkInterfaceAttribute), varargs...) } -// UnassignIpv6AddressesWithContext mocks base method. -func (m *MockEC2) UnassignIpv6AddressesWithContext(arg0 context.Context, arg1 *ec2.UnassignIpv6AddressesInput, arg2 ...request.Option) (*ec2.UnassignIpv6AddressesOutput, error) { +// UnassignIpv6Addresses mocks base method. +func (m *MockEC2) UnassignIpv6Addresses(arg0 context.Context, arg1 *ec2.UnassignIpv6AddressesInput, arg2 ...func(*ec2.Options)) (*ec2.UnassignIpv6AddressesOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "UnassignIpv6AddressesWithContext", varargs...) + ret := m.ctrl.Call(m, "UnassignIpv6Addresses", varargs...) ret0, _ := ret[0].(*ec2.UnassignIpv6AddressesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// UnassignIpv6AddressesWithContext indicates an expected call of UnassignIpv6AddressesWithContext. -func (mr *MockEC2MockRecorder) UnassignIpv6AddressesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// UnassignIpv6Addresses indicates an expected call of UnassignIpv6Addresses. +func (mr *MockEC2MockRecorder) UnassignIpv6Addresses(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnassignIpv6AddressesWithContext", reflect.TypeOf((*MockEC2)(nil).UnassignIpv6AddressesWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnassignIpv6Addresses", reflect.TypeOf((*MockEC2)(nil).UnassignIpv6Addresses), varargs...) } -// UnassignPrivateIpAddressesWithContext mocks base method. -func (m *MockEC2) UnassignPrivateIpAddressesWithContext(arg0 context.Context, arg1 *ec2.UnassignPrivateIpAddressesInput, arg2 ...request.Option) (*ec2.UnassignPrivateIpAddressesOutput, error) { +// UnassignPrivateIpAddresses mocks base method. +func (m *MockEC2) UnassignPrivateIpAddresses(arg0 context.Context, arg1 *ec2.UnassignPrivateIpAddressesInput, arg2 ...func(*ec2.Options)) (*ec2.UnassignPrivateIpAddressesOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "UnassignPrivateIpAddressesWithContext", varargs...) + ret := m.ctrl.Call(m, "UnassignPrivateIpAddresses", varargs...) ret0, _ := ret[0].(*ec2.UnassignPrivateIpAddressesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// UnassignPrivateIpAddressesWithContext indicates an expected call of UnassignPrivateIpAddressesWithContext. -func (mr *MockEC2MockRecorder) UnassignPrivateIpAddressesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// UnassignPrivateIpAddresses indicates an expected call of UnassignPrivateIpAddresses. +func (mr *MockEC2MockRecorder) UnassignPrivateIpAddresses(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnassignPrivateIpAddressesWithContext", reflect.TypeOf((*MockEC2)(nil).UnassignPrivateIpAddressesWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnassignPrivateIpAddresses", reflect.TypeOf((*MockEC2)(nil).UnassignPrivateIpAddresses), varargs...) } diff --git a/pkg/ipamd/ipamd.go b/pkg/ipamd/ipamd.go index 588bc3870a..3ba394ec5e 100644 --- a/pkg/ipamd/ipamd.go +++ b/pkg/ipamd/ipamd.go @@ -24,11 +24,12 @@ import ( "sync/atomic" "time" + "github.com/aws/smithy-go" + "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/aws" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/samber/lo" @@ -306,20 +307,23 @@ func prometheusRegister() { // containsInsufficientCIDRsOrSubnetIPs returns whether a CIDR cannot be carved in the subnet or subnet is running out of IP addresses func containsInsufficientCIDRsOrSubnetIPs(err error) bool { - var awsErr awserr.Error + log.Debugf("containsInsufficientCIDRsOrSubnetIPs encountered %v", err) + var apiErr smithy.APIError // IP exhaustion can be due to Insufficient Cidr blocks or Insufficient Free Address in a Subnet // In these 2 cases we will back off for 2 minutes before retrying - if errors.As(err, &awsErr) { - log.Debugf("Insufficient IP Addresses due to: %v\n", awsErr.Code()) - return awsErr.Code() == INSUFFICIENT_CIDR_BLOCKS || awsErr.Code() == INSUFFICIENT_FREE_IP_SUBNET + if errors.As(err, &apiErr) { + log.Debugf("Insufficient IP Addresses due to: %v\n", apiErr.ErrorCode()) + return apiErr.ErrorCode() == INSUFFICIENT_CIDR_BLOCKS || apiErr.ErrorCode() == INSUFFICIENT_FREE_IP_SUBNET } return false } // containsPrivateIPAddressLimitExceededError returns whether exceeds ENI's IP address limit func containsPrivateIPAddressLimitExceededError(err error) bool { - if aerr, ok := err.(awserr.Error); ok { - return aerr.Code() == "PrivateIpAddressLimitExceeded" + log.Debugf("containsPrivateIPAddressLimitExceededError encountered %v", err) + var apiErr smithy.APIError + if errors.As(err, &apiErr) { + return apiErr.ErrorCode() == "PrivateIpAddressLimitExceeded" } return false } @@ -942,7 +946,7 @@ func (c *IPAMContext) tryAssignIPs() (increasedPool bool, err error) { } } - var ec2ip4s []*ec2.NetworkInterfacePrivateIpAddress + var ec2ip4s []ec2types.NetworkInterfacePrivateIpAddress if containsPrivateIPAddressLimitExceededError(err) { log.Debug("AssignPrivateIpAddresses returned PrivateIpAddressLimitExceeded. This can happen if the data store is out of sync." + "Returning without an error here since we will verify the actual state by calling EC2 to see what addresses have already assigned to this ENI.") @@ -960,7 +964,7 @@ func (c *IPAMContext) tryAssignIPs() (increasedPool bool, err error) { ec2Addrs := output.AssignedPrivateIpAddresses for _, ec2Addr := range ec2Addrs { - ec2ip4s = append(ec2ip4s, &ec2.NetworkInterfacePrivateIpAddress{PrivateIpAddress: aws.String(aws.StringValue(ec2Addr.PrivateIpAddress))}) + ec2ip4s = append(ec2ip4s, ec2types.NetworkInterfacePrivateIpAddress{PrivateIpAddress: ec2Addr.PrivateIpAddress}) } } c.addENIsecondaryIPsToDataStore(ec2ip4s, eni.ID) @@ -996,14 +1000,14 @@ func (c *IPAMContext) assignIPv6Prefix(eniID string) (err error) { return err } for _, v6Prefix := range strPrefixes { - ec2v6Prefixes = append(ec2v6Prefixes, &ec2.Ipv6PrefixSpecification{Ipv6Prefix: v6Prefix}) + ec2v6Prefixes = append(ec2v6Prefixes, ec2types.Ipv6PrefixSpecification{Ipv6Prefix: v6Prefix}) } log.Debugf("Successfully allocated an IPv6Prefix for ENI: %s", eniID) } else if len(ec2v6Prefixes) > 1 { //Found more than one v6 prefix attached to the ENI. VPC CNI will only attach a single v6 prefix //and it will not attempt to free any additional Prefixes that are already attached. //Will use the first IPv6 Prefix attached for IP address allocation. - ec2v6Prefixes = []*ec2.Ipv6PrefixSpecification{ec2v6Prefixes[0]} + ec2v6Prefixes = []ec2types.Ipv6PrefixSpecification{ec2v6Prefixes[0]} } c.addENIv6prefixesToDataStore(ec2v6Prefixes, eniID) return nil @@ -1032,7 +1036,7 @@ func (c *IPAMContext) tryAssignPrefixes() (increasedPool bool, err error) { } } - var ec2Prefixes []*ec2.Ipv4PrefixSpecification + var ec2Prefixes []ec2types.Ipv4PrefixSpecification if containsPrivateIPAddressLimitExceededError(err) { log.Debug("AssignPrivateIpAddresses returned PrivateIpAddressLimitExceeded. This can happen if the data store is out of sync." + "Returning without an error here since we will verify the actual state by calling EC2 to see what addresses have already assigned to this ENI.") @@ -1111,13 +1115,13 @@ func (c *IPAMContext) setupENI(eni string, eniMetadata awsutils.ENIMetadata, isT return nil } -func (c *IPAMContext) addENIsecondaryIPsToDataStore(ec2PrivateIpAddrs []*ec2.NetworkInterfacePrivateIpAddress, eni string) { +func (c *IPAMContext) addENIsecondaryIPsToDataStore(ec2PrivateIpAddrs []ec2types.NetworkInterfacePrivateIpAddress, eni string) { // Add all the secondary IPs for _, ec2PrivateIpAddr := range ec2PrivateIpAddrs { - if aws.BoolValue(ec2PrivateIpAddr.Primary) { + if aws.ToBool(ec2PrivateIpAddr.Primary) { continue } - cidr := net.IPNet{IP: net.ParseIP(aws.StringValue(ec2PrivateIpAddr.PrivateIpAddress)), Mask: net.IPv4Mask(255, 255, 255, 255)} + cidr := net.IPNet{IP: net.ParseIP(aws.ToString(ec2PrivateIpAddr.PrivateIpAddress)), Mask: net.IPv4Mask(255, 255, 255, 255)} err := c.dataStore.AddIPv4CidrToStore(eni, cidr, false) if err != nil && err.Error() != datastore.IPAlreadyInStoreError { log.Warnf("Failed to increase IP pool, failed to add IP %s to data store", ec2PrivateIpAddr.PrivateIpAddress) @@ -1128,10 +1132,10 @@ func (c *IPAMContext) addENIsecondaryIPsToDataStore(ec2PrivateIpAddrs []*ec2.Net c.logPoolStats(c.dataStore.GetIPStats(ipV4AddrFamily)) } -func (c *IPAMContext) addENIv4prefixesToDataStore(ec2PrefixAddrs []*ec2.Ipv4PrefixSpecification, eni string) { +func (c *IPAMContext) addENIv4prefixesToDataStore(ec2PrefixAddrs []ec2types.Ipv4PrefixSpecification, eni string) { // Walk thru all prefixes for _, ec2PrefixAddr := range ec2PrefixAddrs { - strIpv4Prefix := aws.StringValue(ec2PrefixAddr.Ipv4Prefix) + strIpv4Prefix := aws.ToString(ec2PrefixAddr.Ipv4Prefix) _, ipnet, err := net.ParseCIDR(strIpv4Prefix) if err != nil { //Parsing failed, get next prefix @@ -1149,11 +1153,11 @@ func (c *IPAMContext) addENIv4prefixesToDataStore(ec2PrefixAddrs []*ec2.Ipv4Pref c.logPoolStats(c.dataStore.GetIPStats(ipV4AddrFamily)) } -func (c *IPAMContext) addENIv6prefixesToDataStore(ec2PrefixAddrs []*ec2.Ipv6PrefixSpecification, eni string) { +func (c *IPAMContext) addENIv6prefixesToDataStore(ec2PrefixAddrs []ec2types.Ipv6PrefixSpecification, eni string) { log.Debugf("Updating datastore with IPv6Prefix(es) for ENI: %v, count: %v", eni, len(ec2PrefixAddrs)) // Walk through all prefixes for _, ec2PrefixAddr := range ec2PrefixAddrs { - strIpv6Prefix := aws.StringValue(ec2PrefixAddr.Ipv6Prefix) + strIpv6Prefix := aws.ToString(ec2PrefixAddr.Ipv6Prefix) _, ipnet, err := net.ParseCIDR(strIpv6Prefix) if err != nil { // Parsing failed, get next prefix @@ -1541,11 +1545,11 @@ func (c *IPAMContext) eniPrefixPoolReconcile(prefixPool []string, attachedENI aw // verifyAndAddIPsToDatastore updates the datastore with the known secondary IPs. IPs who are out of cooldown gets added // back to the datastore after being verified against EC2. -func (c *IPAMContext) verifyAndAddIPsToDatastore(eni string, attachedENIIPs []*ec2.NetworkInterfacePrivateIpAddress, needEC2Reconcile bool) map[string]bool { - var ec2VerifiedAddresses []*ec2.NetworkInterfacePrivateIpAddress +func (c *IPAMContext) verifyAndAddIPsToDatastore(eni string, attachedENIIPs []ec2types.NetworkInterfacePrivateIpAddress, needEC2Reconcile bool) map[string]bool { + var ec2VerifiedAddresses []ec2types.NetworkInterfacePrivateIpAddress seenIPs := make(map[string]bool) for _, privateIPv4 := range attachedENIIPs { - strPrivateIPv4 := aws.StringValue(privateIPv4.PrivateIpAddress) + strPrivateIPv4 := aws.ToString(privateIPv4.PrivateIpAddress) if strPrivateIPv4 == c.primaryIP[eni] { log.Infof("Reconcile and skip primary IP %s on ENI %s", strPrivateIPv4, eni) continue @@ -1577,7 +1581,7 @@ func (c *IPAMContext) verifyAndAddIPsToDatastore(eni string, attachedENIIPs []*e // Verify that the IP really belongs to this ENI isReallyAttachedToENI := false for _, ec2Addr := range ec2VerifiedAddresses { - if strPrivateIPv4 == aws.StringValue(ec2Addr.PrivateIpAddress) { + if strPrivateIPv4 == aws.ToString(ec2Addr.PrivateIpAddress) { isReallyAttachedToENI = true log.Debugf("Verified that IP %s is attached to ENI %s", strPrivateIPv4, eni) break @@ -1612,11 +1616,11 @@ func (c *IPAMContext) verifyAndAddIPsToDatastore(eni string, attachedENIIPs []*e // verifyAndAddPrefixesToDatastore updates the datastore with the known Prefixes. Prefixes who are out of cooldown gets added // back to the datastore after being verified against EC2. -func (c *IPAMContext) verifyAndAddPrefixesToDatastore(eni string, attachedENIPrefixes []*ec2.Ipv4PrefixSpecification, needEC2Reconcile bool) map[string]bool { - var ec2VerifiedAddresses []*ec2.Ipv4PrefixSpecification +func (c *IPAMContext) verifyAndAddPrefixesToDatastore(eni string, attachedENIPrefixes []ec2types.Ipv4PrefixSpecification, needEC2Reconcile bool) map[string]bool { + var ec2VerifiedAddresses []ec2types.Ipv4PrefixSpecification seenIPs := make(map[string]bool) for _, privateIPv4Cidr := range attachedENIPrefixes { - strPrivateIPv4Cidr := aws.StringValue(privateIPv4Cidr.Ipv4Prefix) + strPrivateIPv4Cidr := aws.ToString(privateIPv4Cidr.Ipv4Prefix) log.Debugf("Check in coolddown Found prefix %s", strPrivateIPv4Cidr) // Check if this Prefix was recently freed @@ -1650,7 +1654,7 @@ func (c *IPAMContext) verifyAndAddPrefixesToDatastore(eni string, attachedENIPre // Verify that the Prefix really belongs to this ENI isReallyAttachedToENI := false for _, ec2Addr := range ec2VerifiedAddresses { - if strPrivateIPv4Cidr == aws.StringValue(ec2Addr.Ipv4Prefix) { + if strPrivateIPv4Cidr == aws.ToString(ec2Addr.Ipv4Prefix) { isReallyAttachedToENI = true log.Debugf("Verified that IP %s is attached to ENI %s", strPrivateIPv4Cidr, eni) break diff --git a/pkg/ipamd/ipamd_test.go b/pkg/ipamd/ipamd_test.go index 7999a5e4a8..ef796ac2e4 100644 --- a/pkg/ipamd/ipamd_test.go +++ b/pkg/ipamd/ipamd_test.go @@ -24,9 +24,10 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/smithy-go" + + "github.com/aws/aws-sdk-go-v2/aws" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/golang/mock/gomock" "github.com/samber/lo" "github.com/stretchr/testify/assert" @@ -368,7 +369,7 @@ func getDummyENIMetadata() (awsutils.ENIMetadata, awsutils.ENIMetadata, awsutils MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, @@ -383,7 +384,7 @@ func getDummyENIMetadata() (awsutils.ENIMetadata, awsutils.ENIMetadata, awsutils MAC: secMAC, DeviceNumber: secDevice, SubnetIPv4CIDR: secSubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr11, Primary: ¬Primary, }, @@ -398,7 +399,7 @@ func getDummyENIMetadata() (awsutils.ENIMetadata, awsutils.ENIMetadata, awsutils MAC: terMAC, DeviceNumber: terDevice, SubnetIPv4CIDR: terSubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr21, Primary: ¬Primary, }, @@ -420,12 +421,12 @@ func getDummyENIMetadataWithPrefix() (awsutils.ENIMetadata, awsutils.ENIMetadata MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, }, - IPv4Prefixes: []*ec2.Ipv4PrefixSpecification{ + IPv4Prefixes: []ec2types.Ipv4PrefixSpecification{ { Ipv4Prefix: &testPrefix1, }, @@ -437,7 +438,7 @@ func getDummyENIMetadataWithPrefix() (awsutils.ENIMetadata, awsutils.ENIMetadata MAC: secMAC, DeviceNumber: secDevice, SubnetIPv4CIDR: secSubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr2, Primary: &primary, }, @@ -455,12 +456,12 @@ func getDummyENIMetadataWithV6Prefix() awsutils.ENIMetadata { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, }, - IPv6Prefixes: []*ec2.Ipv6PrefixSpecification{ + IPv6Prefixes: []ec2types.Ipv6PrefixSpecification{ { Ipv6Prefix: &testv6Prefix, }, @@ -549,7 +550,7 @@ func testIncreaseIPPool(t *testing.T, useENIConfig bool, unschedulabeNode bool, MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, @@ -563,7 +564,7 @@ func testIncreaseIPPool(t *testing.T, useENIConfig bool, unschedulabeNode bool, MAC: secMAC, DeviceNumber: secDevice, SubnetIPv4CIDR: secSubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr11, Primary: ¬Primary, }, @@ -629,11 +630,21 @@ func assertAllocationExternalCalls(shouldCall bool, useENIConfig bool, m *testMo callCount = 1 } + originalErr := errors.New("err") + if useENIConfig { m.awsutils.EXPECT().AllocENI(true, sg, podENIConfig.Subnet, 14).Times(callCount).Return(eni2, nil) } else if subnetDiscovery { - m.awsutils.EXPECT().AllocIPAddresses(primaryENIid, 14).Times(callCount).Return(nil, awserr.New("InsufficientFreeAddressesInSubnet", "", errors.New("err"))) - m.awsutils.EXPECT().AllocIPAddresses(primaryENIid, 1).Times(callCount).Return(nil, awserr.New("InsufficientFreeAddressesInSubnet", "", errors.New("err"))) + m.awsutils.EXPECT().AllocIPAddresses(primaryENIid, 14).Times(callCount).Return(nil, &smithy.GenericAPIError{ + Code: "InsufficientFreeAddressesInSubnet", + Message: originalErr.Error(), + Fault: smithy.FaultUnknown, + }) + m.awsutils.EXPECT().AllocIPAddresses(primaryENIid, 1).Times(callCount).Return(nil, &smithy.GenericAPIError{ + Code: "InsufficientFreeAddressesInSubnet", + Message: originalErr.Error(), + Fault: smithy.FaultUnknown, + }) m.awsutils.EXPECT().AllocENI(false, nil, "", 14).Times(callCount).Return(eni2, nil) } else { m.awsutils.EXPECT().AllocENI(false, nil, "", 14).Times(callCount).Return(eni2, nil) @@ -702,11 +713,21 @@ func testIncreasePrefixPool(t *testing.T, useENIConfig, subnetDiscovery bool) { sg = append(sg, aws.String(sgID)) } + originalErr := errors.New("err") + if useENIConfig { m.awsutils.EXPECT().AllocENI(true, sg, podENIConfig.Subnet, 1).Return(eni2, nil) } else if subnetDiscovery { - m.awsutils.EXPECT().AllocIPAddresses(primaryENIid, 1).Return(nil, awserr.New("InsufficientFreeAddressesInSubnet", "", errors.New("err"))) - m.awsutils.EXPECT().AllocIPAddresses(primaryENIid, 1).Return(nil, awserr.New("InsufficientFreeAddressesInSubnet", "", errors.New("err"))) + m.awsutils.EXPECT().AllocIPAddresses(primaryENIid, 1).Return(nil, &smithy.GenericAPIError{ + Code: "InsufficientFreeAddressesInSubnet", + Message: originalErr.Error(), + Fault: smithy.FaultUnknown, + }) + m.awsutils.EXPECT().AllocIPAddresses(primaryENIid, 1).Return(nil, &smithy.GenericAPIError{ + Code: "InsufficientFreeAddressesInSubnet", + Message: originalErr.Error(), + Fault: smithy.FaultUnknown, + }) m.awsutils.EXPECT().AllocENI(false, nil, "", 1).Return(eni2, nil) } else { m.awsutils.EXPECT().AllocENI(false, nil, "", 1).Return(eni2, nil) @@ -718,12 +739,12 @@ func testIncreasePrefixPool(t *testing.T, useENIConfig, subnetDiscovery bool) { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, }, - IPv4Prefixes: []*ec2.Ipv4PrefixSpecification{ + IPv4Prefixes: []ec2types.Ipv4PrefixSpecification{ { Ipv4Prefix: &testPrefix1, }, @@ -734,12 +755,12 @@ func testIncreasePrefixPool(t *testing.T, useENIConfig, subnetDiscovery bool) { MAC: secMAC, DeviceNumber: secDevice, SubnetIPv4CIDR: secSubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr11, Primary: &primary, }, }, - IPv4Prefixes: []*ec2.Ipv4PrefixSpecification{ + IPv4Prefixes: []ec2types.Ipv4PrefixSpecification{ { Ipv4Prefix: &testPrefix2, }, @@ -872,7 +893,7 @@ func TestTryAddIPToENI(t *testing.T) { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, @@ -886,7 +907,7 @@ func TestTryAddIPToENI(t *testing.T) { MAC: secMAC, DeviceNumber: secDevice, SubnetIPv4CIDR: secSubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr11, Primary: ¬Primary, }, @@ -960,7 +981,7 @@ func TestNodeIPPoolReconcile(t *testing.T) { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, @@ -1059,7 +1080,7 @@ func TestNodePrefixPoolReconcile(t *testing.T) { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, @@ -1676,7 +1697,7 @@ func TestNodeIPPoolReconcileBadIMDSData(t *testing.T) { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, @@ -1698,7 +1719,7 @@ func TestNodeIPPoolReconcileBadIMDSData(t *testing.T) { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, @@ -1762,7 +1783,7 @@ func TestNodePrefixPoolReconcileBadIMDSData(t *testing.T) { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, @@ -1784,7 +1805,7 @@ func TestNodePrefixPoolReconcileBadIMDSData(t *testing.T) { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, @@ -1819,7 +1840,7 @@ func getPrimaryENIMetadata() awsutils.ENIMetadata { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, @@ -1844,7 +1865,7 @@ func getSecondaryENIMetadata() awsutils.ENIMetadata { MAC: secMAC, DeviceNumber: secDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr3, Primary: &primary, }, @@ -1866,12 +1887,12 @@ func getPrimaryENIMetadataPDenabled() awsutils.ENIMetadata { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, }, - IPv4Prefixes: []*ec2.Ipv4PrefixSpecification{ + IPv4Prefixes: []ec2types.Ipv4PrefixSpecification{ { Ipv4Prefix: &testPrefix1, }, @@ -1890,12 +1911,12 @@ func getSecondaryENIMetadataPDenabled() awsutils.ENIMetadata { MAC: secMAC, DeviceNumber: secDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr3, Primary: &primary, }, }, - IPv4Prefixes: []*ec2.Ipv4PrefixSpecification{ + IPv4Prefixes: []ec2types.Ipv4PrefixSpecification{ { Ipv4Prefix: &testPrefix2, }, @@ -1926,7 +1947,7 @@ func TestIPAMContext_setupENI(t *testing.T) { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, @@ -1972,7 +1993,7 @@ func TestIPAMContext_setupENIwithPDenabled(t *testing.T) { MAC: primaryMAC, DeviceNumber: primaryDevice, SubnetIPv4CIDR: primarySubnet, - IPv4Addresses: []*ec2.NetworkInterfacePrivateIpAddress{ + IPv4Addresses: []ec2types.NetworkInterfacePrivateIpAddress{ { PrivateIpAddress: &testAddr1, Primary: &primary, }, diff --git a/pkg/publisher/generate_mocks.go b/pkg/publisher/generate_mocks.go new file mode 100644 index 0000000000..50531740ff --- /dev/null +++ b/pkg/publisher/generate_mocks.go @@ -0,0 +1,16 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +package publisher + +//go:generate go run github.com/golang/mock/mockgen -source=publisher.go -destination mock_publisher/mock_publisher.go -copyright_file ../../scripts/copyright.txt . diff --git a/pkg/publisher/mock_publisher/mock_publisher.go b/pkg/publisher/mock_publisher/mock_publisher.go index 49ae6d93a6..7680febbc0 100644 --- a/pkg/publisher/mock_publisher/mock_publisher.go +++ b/pkg/publisher/mock_publisher/mock_publisher.go @@ -1,3 +1,17 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + // Code generated by MockGen. DO NOT EDIT. // Source: publisher.go @@ -5,64 +19,116 @@ package mock_publisher import ( - cloudwatch "github.com/aws/aws-sdk-go/service/cloudwatch" - gomock "github.com/golang/mock/gomock" + context "context" reflect "reflect" + + cloudwatch "github.com/aws/aws-sdk-go-v2/service/cloudwatch" + types "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" + gomock "github.com/golang/mock/gomock" ) -// MockPublisher is a mock of Publisher interface +// MockcloudWatchAPI is a mock of cloudWatchAPI interface. +type MockcloudWatchAPI struct { + ctrl *gomock.Controller + recorder *MockcloudWatchAPIMockRecorder +} + +// MockcloudWatchAPIMockRecorder is the mock recorder for MockcloudWatchAPI. +type MockcloudWatchAPIMockRecorder struct { + mock *MockcloudWatchAPI +} + +// NewMockcloudWatchAPI creates a new mock instance. +func NewMockcloudWatchAPI(ctrl *gomock.Controller) *MockcloudWatchAPI { + mock := &MockcloudWatchAPI{ctrl: ctrl} + mock.recorder = &MockcloudWatchAPIMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockcloudWatchAPI) EXPECT() *MockcloudWatchAPIMockRecorder { + return m.recorder +} + +// PutMetricData mocks base method. +func (m *MockcloudWatchAPI) PutMetricData(ctx context.Context, params *cloudwatch.PutMetricDataInput, optFns ...func(*cloudwatch.Options)) (*cloudwatch.PutMetricDataOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, params} + for _, a := range optFns { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "PutMetricData", varargs...) + ret0, _ := ret[0].(*cloudwatch.PutMetricDataOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PutMetricData indicates an expected call of PutMetricData. +func (mr *MockcloudWatchAPIMockRecorder) PutMetricData(ctx, params interface{}, optFns ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, params}, optFns...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutMetricData", reflect.TypeOf((*MockcloudWatchAPI)(nil).PutMetricData), varargs...) +} + +// MockPublisher is a mock of Publisher interface. type MockPublisher struct { ctrl *gomock.Controller recorder *MockPublisherMockRecorder } -// MockPublisherMockRecorder is the mock recorder for MockPublisher +// MockPublisherMockRecorder is the mock recorder for MockPublisher. type MockPublisherMockRecorder struct { mock *MockPublisher } -// NewMockPublisher creates a new mock instance +// NewMockPublisher creates a new mock instance. func NewMockPublisher(ctrl *gomock.Controller) *MockPublisher { mock := &MockPublisher{ctrl: ctrl} mock.recorder = &MockPublisherMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockPublisher) EXPECT() *MockPublisherMockRecorder { return m.recorder } -// Publish mocks base method -func (m *MockPublisher) Publish(metricDataPoints ...*cloudwatch.MetricDatum) { +// Publish mocks base method. +func (m *MockPublisher) Publish(metricsDataPoints ...types.MetricDatum) { + m.ctrl.T.Helper() varargs := []interface{}{} - for _, a := range metricDataPoints { + for _, a := range metricsDataPoints { varargs = append(varargs, a) } m.ctrl.Call(m, "Publish", varargs...) } -// Publish indicates an expected call of Publish -func (mr *MockPublisherMockRecorder) Publish(metricDataPoints ...interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Publish", reflect.TypeOf((*MockPublisher)(nil).Publish), metricDataPoints...) +// Publish indicates an expected call of Publish. +func (mr *MockPublisherMockRecorder) Publish(metricsDataPoints ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Publish", reflect.TypeOf((*MockPublisher)(nil).Publish), metricsDataPoints...) } -// Start mocks base method +// Start mocks base method. func (m *MockPublisher) Start(publishInterval int) { + m.ctrl.T.Helper() m.ctrl.Call(m, "Start", publishInterval) } -// Start indicates an expected call of Start -func (mr *MockPublisherMockRecorder) Start() *gomock.Call { - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockPublisher)(nil).Start)) +// Start indicates an expected call of Start. +func (mr *MockPublisherMockRecorder) Start(publishInterval interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockPublisher)(nil).Start), publishInterval) } -// Stop mocks base method +// Stop mocks base method. func (m *MockPublisher) Stop() { + m.ctrl.T.Helper() m.ctrl.Call(m, "Stop") } -// Stop indicates an expected call of Stop +// Stop indicates an expected call of Stop. func (mr *MockPublisherMockRecorder) Stop() *gomock.Call { + mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockPublisher)(nil).Stop)) } diff --git a/pkg/publisher/publisher.go b/pkg/publisher/publisher.go index d22df68e4c..598e09b40d 100644 --- a/pkg/publisher/publisher.go +++ b/pkg/publisher/publisher.go @@ -19,9 +19,11 @@ import ( "sync" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" + ec2metadata "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudwatch" + types "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" "github.com/pkg/errors" "github.com/aws/amazon-vpc-cni-k8s/pkg/awsutils/awssession" @@ -56,10 +58,15 @@ var ( } ) +// cloudWatchAPI defines the interface with methods required from CloudWatch Service +type cloudWatchAPI interface { + PutMetricData(ctx context.Context, params *cloudwatch.PutMetricDataInput, optFns ...func(*cloudwatch.Options)) (*cloudwatch.PutMetricDataOutput, error) +} + // Publisher defines the interface to publish one or more data points type Publisher interface { // Publish publishes one or more metric data points - Publish(metricDataPoints ...*cloudwatch.MetricDatum) + Publish(metricsDataPoints ...types.MetricDatum) // Start is to initiate the batch and publish operation Start(publishInterval int) @@ -75,8 +82,8 @@ type cloudWatchPublisher struct { cancel context.CancelFunc updateIntervalTicker *time.Ticker clusterID string - cloudwatchClient cloudwatchiface.CloudWatchAPI - localMetricData []*cloudwatch.MetricDatum + cloudwatchClient cloudWatchAPI + localMetricData []types.MetricDatum lock sync.RWMutex log logger.Logger } @@ -88,38 +95,39 @@ type cloudWatchPublisher struct { // not specified clusterID then its a Cx error // New returns a new instance of `Publisher` func New(ctx context.Context, region string, clusterID string, log logger.Logger) (Publisher, error) { - sess := awssession.New() + ctx = context.Background() + cfg, err := awssession.New(ctx) + if err != nil { + return nil, err + } // If Customers have explicitly specified clusterID then skip generating it if clusterID == "" { - ec2Client, err := ec2wrapper.NewMetricsClient() + ec2client, err := ec2wrapper.NewMetricsClient() if err != nil { return nil, errors.Wrap(err, "publisher: unable to obtain EC2 service client") } - - clusterID = getClusterID(ec2Client, log) + clusterID = getClusterID(ec2client, log) } // Try to fetch region if not available if region == "" { // Get ec2metadata client - ec2MetadataClient := ec2metadatawrapper.New(sess) - val, err := ec2MetadataClient.Region() + ec2Metadataclient, err := ec2metadatawrapper.New(ctx) if err != nil { - return nil, errors.Wrap(err, "publisher: Unable to obtain region") + return nil, err + } + output, err := ec2Metadataclient.GetRegion(ctx, &ec2metadata.GetRegionInput{}) + region = output.Region + if err != nil { + return nil, err } - region = val } log.Infof("Using REGION=%s and CLUSTER_ID=%s", region, clusterID) - // Get AWS session - awsCfg := aws.Config{ - Region: aws.String(region), - } - sess = sess.Copy(&awsCfg) - // Get CloudWatch client - cloudwatchClient := cloudwatch.New(sess) + cfg.Region = region + cloudwatchClient := cloudwatch.NewFromConfig(cfg) // Build derived context derivedContext, cancel := context.WithCancel(ctx) @@ -129,7 +137,7 @@ func New(ctx context.Context, region string, clusterID string, log logger.Logger cancel: cancel, cloudwatchClient: cloudwatchClient, clusterID: clusterID, - localMetricData: make([]*cloudwatch.MetricDatum, 0, localMetricDataSize), + localMetricData: make([]types.MetricDatum, 0, localMetricDataSize), log: log, }, nil } @@ -148,11 +156,10 @@ func (p *cloudWatchPublisher) Stop() { } // Publish is a variadic function to publish one or more metric data points -func (p *cloudWatchPublisher) Publish(metricDataPoints ...*cloudwatch.MetricDatum) { +func (p *cloudWatchPublisher) Publish(metricDataPoints ...types.MetricDatum) { // Fetch dimensions for override p.log.Info("Fetching CloudWatch dimensions") dimensions := p.getCloudWatchMetricDatumDimensions() - // Grab lock p.lock.Lock() defer p.lock.Unlock() @@ -167,24 +174,24 @@ func (p *cloudWatchPublisher) Publish(metricDataPoints ...*cloudwatch.MetricDatu func (p *cloudWatchPublisher) pushLocal() { p.lock.Lock() data := p.localMetricData[:] - p.localMetricData = make([]*cloudwatch.MetricDatum, 0, localMetricDataSize) + p.localMetricData = make([]types.MetricDatum, 0, localMetricDataSize) p.lock.Unlock() p.push(data) } -func (p *cloudWatchPublisher) push(metricData []*cloudwatch.MetricDatum) { +func (p *cloudWatchPublisher) push(metricData []types.MetricDatum) { if len(metricData) == 0 { p.log.Info("Missing data for publishing CloudWatch metrics") return } // Setup input - input := cloudwatch.PutMetricDataInput{} - input.Namespace = p.getCloudWatchMetricNamespace() + input := &cloudwatch.PutMetricDataInput{ + Namespace: aws.String(cloudwatchMetricNamespace), + } - // NOTE: Ensure cap of 40K per request and enforce rate limiting for len(metricData) > 0 { - input.MetricData = metricData[:maxDataPoints] + input.MetricData = metricData[:min(maxDataPoints, len(metricData))] // Publish data err := p.send(input) @@ -193,18 +200,18 @@ func (p *cloudWatchPublisher) push(metricData []*cloudwatch.MetricDatum) { } // Mutate slice - index := min(maxDataPoints, len(metricData)) - metricData = metricData[index:] + + metricData = metricData[min(maxDataPoints, len(metricData)):] // Reset Input - input = cloudwatch.PutMetricDataInput{} - input.Namespace = p.getCloudWatchMetricNamespace() + input.MetricData = nil } } -func (p *cloudWatchPublisher) send(input cloudwatch.PutMetricDataInput) error { +// Why is there a *cloudwatch.PutMetricDataInput and cloudwatch.PutMetricDataInput? +func (p *cloudWatchPublisher) send(input *cloudwatch.PutMetricDataInput) error { p.log.Info("Sending data to CloudWatch metrics") - _, err := p.cloudwatchClient.PutMetricData(&input) + _, err := p.cloudwatchClient.PutMetricData(p.ctx, input) return err } @@ -242,8 +249,8 @@ func getClusterID(ec2Client *ec2wrapper.EC2Wrapper, log logger.Logger) string { return clusterID } -func (p *cloudWatchPublisher) getCloudWatchMetricDatumDimensions() []*cloudwatch.Dimension { - return []*cloudwatch.Dimension{ +func (p *cloudWatchPublisher) getCloudWatchMetricDatumDimensions() []types.Dimension { + return []types.Dimension{ { Name: aws.String(clusterIDDimension), Value: aws.String(p.clusterID), diff --git a/pkg/publisher/publisher_test.go b/pkg/publisher/publisher_test.go index 7cc06b5dd7..ea8e4dc5d8 100644 --- a/pkg/publisher/publisher_test.go +++ b/pkg/publisher/publisher_test.go @@ -19,12 +19,12 @@ import ( "testing" "time" - "github.com/aws/amazon-vpc-cni-k8s/pkg/utils/logger" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/pkg/errors" + + "github.com/aws/amazon-vpc-cni-k8s/pkg/utils/logger" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudwatch" + "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" "github.com/stretchr/testify/assert" ) @@ -50,10 +50,16 @@ func TestCloudWatchPublisherWithNoIMDS(t *testing.T) { func TestCloudWatchPublisherWithSingleDatum(t *testing.T) { cloudwatchPublisher := getCloudWatchPublisher(t) - testCloudwatchMetricDatum := &cloudwatch.MetricDatum{ + testCloudwatchMetricDatum := types.MetricDatum{ MetricName: aws.String(testMetricOne), - Unit: aws.String(cloudwatch.StandardUnitNone), + Unit: types.StandardUnitNone, Value: aws.Float64(1.0), + Dimensions: []types.Dimension{ + { + Name: aws.String(clusterIDDimension), + Value: aws.String(testClusterID), + }, + }, } cloudwatchPublisher.Publish(testCloudwatchMetricDatum) @@ -67,13 +73,13 @@ func TestCloudWatchPublisherWithSingleDatum(t *testing.T) { func TestCloudWatchPublisherWithMultipleDatum(t *testing.T) { cloudwatchPublisher := getCloudWatchPublisher(t) - var metricDataPoints []*cloudwatch.MetricDatum + var metricDataPoints []types.MetricDatum for i := 0; i < 10; i++ { metricName := "TEST_METRIC_" + strconv.Itoa(i) - testCloudwatchMetricDatum := &cloudwatch.MetricDatum{ + testCloudwatchMetricDatum := types.MetricDatum{ MetricName: aws.String(metricName), - Unit: aws.String(cloudwatch.StandardUnitNone), + Unit: types.StandardUnitNone, Value: aws.Float64(1.0), } metricDataPoints = append(metricDataPoints, testCloudwatchMetricDatum) @@ -89,13 +95,13 @@ func TestCloudWatchPublisherWithMultipleDatum(t *testing.T) { func TestCloudWatchPublisherWithGreaterThanMaxDatapoints(t *testing.T) { cloudwatchPublisher := getCloudWatchPublisher(t) - var metricDataPoints []*cloudwatch.MetricDatum + var metricDataPoints []types.MetricDatum for i := 0; i < 30; i++ { metricName := "TEST_METRIC_" + strconv.Itoa(i) - testCloudwatchMetricDatum := &cloudwatch.MetricDatum{ + testCloudwatchMetricDatum := types.MetricDatum{ MetricName: aws.String(metricName), - Unit: aws.String(cloudwatch.StandardUnitNone), + Unit: types.StandardUnitNone, Value: aws.Float64(1.0), } metricDataPoints = append(metricDataPoints, testCloudwatchMetricDatum) @@ -111,12 +117,12 @@ func TestCloudWatchPublisherWithGreaterThanMaxDatapoints(t *testing.T) { func TestCloudWatchPublisherWithGreaterThanMaxDatapointsAndStop(t *testing.T) { cloudwatchPublisher := getCloudWatchPublisher(t) - var metricDataPoints []*cloudwatch.MetricDatum + var metricDataPoints []types.MetricDatum for i := 0; i < 30; i++ { metricName := "TEST_METRIC_" + strconv.Itoa(i) - testCloudwatchMetricDatum := &cloudwatch.MetricDatum{ + testCloudwatchMetricDatum := types.MetricDatum{ MetricName: aws.String(metricName), - Unit: aws.String(cloudwatch.StandardUnitNone), + Unit: types.StandardUnitNone, Value: aws.Float64(1.0), } metricDataPoints = append(metricDataPoints, testCloudwatchMetricDatum) @@ -138,21 +144,30 @@ func TestCloudWatchPublisherWithGreaterThanMaxDatapointsAndStop(t *testing.T) { func TestCloudWatchPublisherWithSingleDatumWithError(t *testing.T) { derivedContext, cancel := context.WithCancel(context.TODO()) - mockCloudWatch := mockCloudWatchClient{mockPutMetricDataError: errors.New("test error")} + // Create a mock cloudwatch client that will return an error when PutMetricData is called + mockCloudWatch := mockCloudWatchClient{ + mockPutMetricDataError: errors.New("error"), + } cloudwatchPublisher := &cloudWatchPublisher{ ctx: derivedContext, cancel: cancel, - cloudwatchClient: mockCloudWatch, + cloudwatchClient: &mockCloudWatch, clusterID: testClusterID, - localMetricData: make([]*cloudwatch.MetricDatum, 0, localMetricDataSize), + localMetricData: make([]types.MetricDatum, 0, localMetricDataSize), log: getCloudWatchLog(), } - testCloudwatchMetricDatum := &cloudwatch.MetricDatum{ + testCloudwatchMetricDatum := types.MetricDatum{ MetricName: aws.String(testMetricOne), - Unit: aws.String(cloudwatch.StandardUnitNone), + Unit: types.StandardUnitNone, Value: aws.Float64(1.0), + Dimensions: []types.Dimension{ + { + Name: aws.String(clusterIDDimension), + Value: aws.String(testClusterID), + }, + }, } cloudwatchPublisher.Publish(testCloudwatchMetricDatum) @@ -167,13 +182,13 @@ func TestGetCloudWatchMetricNamespace(t *testing.T) { cloudwatchPublisher := getCloudWatchPublisher(t) testNamespace := cloudwatchPublisher.getCloudWatchMetricNamespace() - assert.Equal(t, aws.StringValue(testNamespace), cloudwatchMetricNamespace) + assert.Equal(t, aws.ToString(testNamespace), cloudwatchMetricNamespace) } func TestGetCloudWatchMetricDatumDimensions(t *testing.T) { cloudwatchPublisher := getCloudWatchPublisher(t) - expectedCloudwatchDimensions := []*cloudwatch.Dimension{ + expectedCloudwatchDimensions := []types.Dimension{ { Name: aws.String(clusterIDDimension), Value: aws.String(testClusterID), @@ -187,7 +202,7 @@ func TestGetCloudWatchMetricDatumDimensions(t *testing.T) { func TestGetCloudWatchMetricDatumDimensionsWithMissingClusterID(t *testing.T) { cloudwatchPublisher := &cloudWatchPublisher{log: getCloudWatchLog()} - expectedCloudwatchDimensions := []*cloudwatch.Dimension{ + expectedCloudwatchDimensions := []types.Dimension{ { Name: aws.String(clusterIDDimension), Value: aws.String(""), @@ -201,7 +216,7 @@ func TestGetCloudWatchMetricDatumDimensionsWithMissingClusterID(t *testing.T) { func TestPublishWithNoData(t *testing.T) { cloudwatchPublisher := &cloudWatchPublisher{log: getCloudWatchLog()} - testMetricDataPoints := []*cloudwatch.MetricDatum{} + testMetricDataPoints := []types.MetricDatum{} cloudwatchPublisher.Publish(testMetricDataPoints...) assert.Empty(t, cloudwatchPublisher.localMetricData) @@ -209,7 +224,7 @@ func TestPublishWithNoData(t *testing.T) { func TestPushWithMissingData(t *testing.T) { cloudwatchPublisher := &cloudWatchPublisher{log: getCloudWatchLog()} - testMetricDataPoints := []*cloudwatch.MetricDatum{} + testMetricDataPoints := []types.MetricDatum{} cloudwatchPublisher.push(testMetricDataPoints) assert.Empty(t, cloudwatchPublisher.localMetricData) @@ -225,16 +240,18 @@ func TestMin(t *testing.T) { assert.Equal(t, minimum, a) } -// mockCloudWatchClient is used to facilitate testing +// mockCloudWatchClient is used to facilitate testing and implements the cloudwatch.Client interface type mockCloudWatchClient struct { - cloudwatchiface.CloudWatchAPI + cloudwatch.Client mockPutMetricDataError error } -func (m mockCloudWatchClient) PutMetricData(input *cloudwatch.PutMetricDataInput) (*cloudwatch.PutMetricDataOutput, error) { +func (m *mockCloudWatchClient) PutMetricData(ctx context.Context, params *cloudwatch.PutMetricDataInput, optFns ...func(*cloudwatch.Options)) (*cloudwatch.PutMetricDataOutput, error) { return &cloudwatch.PutMetricDataOutput{}, m.mockPutMetricDataError } +// Implement other methods of the cloudwatch.Client interface as needed for testing. + func getCloudWatchLog() logger.Logger { logConfig := logger.Configuration{ LogLevel: "Debug", @@ -250,9 +267,9 @@ func getCloudWatchPublisher(t *testing.T) *cloudWatchPublisher { return &cloudWatchPublisher{ ctx: derivedContext, cancel: cancel, - cloudwatchClient: mockCloudWatchClient{}, + cloudwatchClient: &mockCloudWatchClient{}, clusterID: testClusterID, - localMetricData: make([]*cloudwatch.MetricDatum, 0, localMetricDataSize), + localMetricData: make([]types.MetricDatum, 0, localMetricDataSize), log: getCloudWatchLog(), } } diff --git a/pkg/utils/cniutils/cni_utils.go b/pkg/utils/cniutils/cni_utils.go index bf5520d12a..31e5a3f68d 100644 --- a/pkg/utils/cniutils/cni_utils.go +++ b/pkg/utils/cniutils/cni_utils.go @@ -13,7 +13,7 @@ import ( "github.com/aws/amazon-vpc-cni-k8s/pkg/netlinkwrapper" "github.com/aws/amazon-vpc-cni-k8s/pkg/procsyswrapper" "github.com/aws/amazon-vpc-cni-k8s/utils/imds" - "github.com/aws/aws-sdk-go/service/ec2" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" ) const ( @@ -148,7 +148,7 @@ func IsIptableTargetNotExist(err error) bool { } // PrefixSimilar checks if prefix pool and eni prefix are equivalent. -func PrefixSimilar(prefixPool []string, eniPrefixes []*ec2.Ipv4PrefixSpecification) bool { +func PrefixSimilar(prefixPool []string, eniPrefixes []ec2types.Ipv4PrefixSpecification) bool { if len(prefixPool) != len(eniPrefixes) { return false } @@ -159,7 +159,7 @@ func PrefixSimilar(prefixPool []string, eniPrefixes []*ec2.Ipv4PrefixSpecificati } for _, prefix := range eniPrefixes { - if prefix == nil || prefix.Ipv4Prefix == nil { + if prefix.Ipv4Prefix == nil { return false } if _, exists := prefixPoolSet[*prefix.Ipv4Prefix]; !exists { @@ -170,7 +170,7 @@ func PrefixSimilar(prefixPool []string, eniPrefixes []*ec2.Ipv4PrefixSpecificati } // IPsSimilar checks if ipPool and eniIPs are equivalent. -func IPsSimilar(ipPool []string, eniIPs []*ec2.NetworkInterfacePrivateIpAddress) bool { +func IPsSimilar(ipPool []string, eniIPs []ec2types.NetworkInterfacePrivateIpAddress) bool { // Here we do +1 in ipPool because eniIPs will also have primary IP which is not used by pods. if len(ipPool)+1 != len(eniIPs) { return false @@ -182,7 +182,7 @@ func IPsSimilar(ipPool []string, eniIPs []*ec2.NetworkInterfacePrivateIpAddress) } for _, ip := range eniIPs { - if ip == nil || ip.PrivateIpAddress == nil || ip.Primary == nil { + if ip.PrivateIpAddress == nil || ip.Primary == nil { return false } if *ip.Primary { diff --git a/pkg/utils/cniutils/cni_utils_test.go b/pkg/utils/cniutils/cni_utils_test.go index 46e063ac42..e8cb7530d2 100644 --- a/pkg/utils/cniutils/cni_utils_test.go +++ b/pkg/utils/cniutils/cni_utils_test.go @@ -4,8 +4,9 @@ import ( "net" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" + + "github.com/aws/aws-sdk-go-v2/aws" current "github.com/containernetworking/cni/pkg/types/100" "github.com/stretchr/testify/assert" ) @@ -214,25 +215,25 @@ func TestPrefixSimilar(t *testing.T) { tests := []struct { name string prefixPool []string - eniPrefixes []*ec2.Ipv4PrefixSpecification + eniPrefixes []ec2types.Ipv4PrefixSpecification want bool }{ { name: "Empty slices", prefixPool: []string{}, - eniPrefixes: []*ec2.Ipv4PrefixSpecification{}, + eniPrefixes: []ec2types.Ipv4PrefixSpecification{}, want: true, }, { name: "Different lengths", prefixPool: []string{"192.168.1.0/24"}, - eniPrefixes: []*ec2.Ipv4PrefixSpecification{}, + eniPrefixes: []ec2types.Ipv4PrefixSpecification{}, want: false, }, { name: "Equivalent prefixes", prefixPool: []string{"192.168.1.0/24", "10.0.0.0/16"}, - eniPrefixes: []*ec2.Ipv4PrefixSpecification{ + eniPrefixes: []ec2types.Ipv4PrefixSpecification{ {Ipv4Prefix: stringPtr("192.168.1.0/24")}, {Ipv4Prefix: stringPtr("10.0.0.0/16")}, }, @@ -241,7 +242,7 @@ func TestPrefixSimilar(t *testing.T) { { name: "Different prefixes", prefixPool: []string{"192.168.1.0/24", "10.0.0.0/16"}, - eniPrefixes: []*ec2.Ipv4PrefixSpecification{ + eniPrefixes: []ec2types.Ipv4PrefixSpecification{ {Ipv4Prefix: stringPtr("192.168.1.0/24")}, {Ipv4Prefix: stringPtr("172.16.0.0/16")}, }, @@ -250,8 +251,8 @@ func TestPrefixSimilar(t *testing.T) { { name: "Nil prefix", prefixPool: []string{"192.168.1.0/24"}, - eniPrefixes: []*ec2.Ipv4PrefixSpecification{ - nil, + eniPrefixes: []ec2types.Ipv4PrefixSpecification{ + {}, }, want: false, }, @@ -270,13 +271,13 @@ func TestIPsSimilar(t *testing.T) { tests := []struct { name string ipPool []string - eniIPs []*ec2.NetworkInterfacePrivateIpAddress + eniIPs []ec2types.NetworkInterfacePrivateIpAddress want bool }{ { name: "Empty IP pool", ipPool: []string{}, - eniIPs: []*ec2.NetworkInterfacePrivateIpAddress{ + eniIPs: []ec2types.NetworkInterfacePrivateIpAddress{ {PrivateIpAddress: stringPtr("10.0.0.1"), Primary: boolPtr(true)}, }, want: true, @@ -284,7 +285,7 @@ func TestIPsSimilar(t *testing.T) { { name: "Different lengths", ipPool: []string{"192.168.1.1"}, - eniIPs: []*ec2.NetworkInterfacePrivateIpAddress{ + eniIPs: []ec2types.NetworkInterfacePrivateIpAddress{ {PrivateIpAddress: stringPtr("10.0.0.1"), Primary: boolPtr(true)}, {PrivateIpAddress: stringPtr("192.168.1.1"), Primary: boolPtr(false)}, {PrivateIpAddress: stringPtr("192.168.1.2"), Primary: boolPtr(false)}, @@ -294,7 +295,7 @@ func TestIPsSimilar(t *testing.T) { { name: "Equivalent IPs", ipPool: []string{"192.168.1.1", "10.0.0.2"}, - eniIPs: []*ec2.NetworkInterfacePrivateIpAddress{ + eniIPs: []ec2types.NetworkInterfacePrivateIpAddress{ {PrivateIpAddress: stringPtr("10.0.0.1"), Primary: boolPtr(true)}, {PrivateIpAddress: stringPtr("192.168.1.1"), Primary: boolPtr(false)}, {PrivateIpAddress: stringPtr("10.0.0.2"), Primary: boolPtr(false)}, @@ -304,7 +305,7 @@ func TestIPsSimilar(t *testing.T) { { name: "Different IPs", ipPool: []string{"192.168.1.1", "10.0.0.2"}, - eniIPs: []*ec2.NetworkInterfacePrivateIpAddress{ + eniIPs: []ec2types.NetworkInterfacePrivateIpAddress{ {PrivateIpAddress: stringPtr("10.0.0.1"), Primary: boolPtr(true)}, {PrivateIpAddress: stringPtr("192.168.1.1"), Primary: boolPtr(false)}, {PrivateIpAddress: stringPtr("172.16.0.1"), Primary: boolPtr(false)}, @@ -314,9 +315,9 @@ func TestIPsSimilar(t *testing.T) { { name: "Nil IP", ipPool: []string{"192.168.1.1"}, - eniIPs: []*ec2.NetworkInterfacePrivateIpAddress{ + eniIPs: []ec2types.NetworkInterfacePrivateIpAddress{ {PrivateIpAddress: stringPtr("10.0.0.1"), Primary: boolPtr(true)}, - nil, + {}, }, want: false, }, diff --git a/pkg/vpc/vpc.go b/pkg/vpc/vpc.go index 00efbc3ca0..a604a1b30d 100644 --- a/pkg/vpc/vpc.go +++ b/pkg/vpc/vpc.go @@ -15,6 +15,8 @@ package vpc import ( "errors" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/aws/amazon-vpc-cni-k8s/pkg/utils/logger" ) @@ -86,7 +88,7 @@ func GetHypervisorType(instanceType string) (string, error) { log.Errorf("%s: %s", instanceType, ErrInstanceTypeNotExist) return "", ErrInstanceTypeNotExist } - return instance.HypervisorType, nil + return string(instance.HypervisorType), nil } func GetIsBareMetal(instanceType string) (bool, error) { @@ -119,7 +121,7 @@ func GetInstance(instanceType string) (InstanceTypeLimits, bool) { return instance, ok } -func SetInstance(instanceType string, eniLimit int, ipv4Limit int, defaultNetworkCardIndex int, networkCards []NetworkCard, hypervisorType string, isBareMetalInstance bool) { - instanceNetworkingLimits[instanceType] = New(eniLimit, ipv4Limit, defaultNetworkCardIndex, networkCards, - hypervisorType, isBareMetalInstance) +func SetInstance(instanceType ec2types.InstanceType, eniLimit int, ipv4Limit int, defaultNetworkCardIndex int, networkCards []NetworkCard, hypervisorType ec2types.InstanceTypeHypervisor, isBareMetalInstance bool) { + instanceNetworkingLimits[string(instanceType)] = New(eniLimit, ipv4Limit, defaultNetworkCardIndex, networkCards, + string(hypervisorType), isBareMetalInstance) } diff --git a/scripts/gen_vpc_ip_limits.go b/scripts/gen_vpc_ip_limits.go index 85c656b4cc..43f8a81ca2 100644 --- a/scripts/gen_vpc_ip_limits.go +++ b/scripts/gen_vpc_ip_limits.go @@ -16,6 +16,7 @@ package main import ( + "context" "fmt" "os" "reflect" @@ -23,13 +24,14 @@ import ( "strconv" "text/template" + "github.com/aws/aws-sdk-go-v2/aws" + + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/amazon-vpc-cni-k8s/pkg/utils/logger" "github.com/aws/amazon-vpc-cni-k8s/pkg/vpc" - "github.com/aws/aws-sdk-go/aws" - - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2" ) const ipLimitFileName = "pkg/vpc/vpc_ip_resource_limit.go" @@ -44,11 +46,20 @@ func printPodLimit(instanceType string, l vpc.InstanceTypeLimits) string { } func main() { + ctx := context.Background() + + cfg, err := config.LoadDefaultConfig(ctx) + + if err != nil { + log.Fatalf("Failed to load configuration: %v", err) + } + // Get instance types limits across all regions - regions := describeRegions() + regions := describeRegions(ctx, cfg) + eniLimitMap := make(map[string]vpc.InstanceTypeLimits) for _, region := range regions { - describeInstanceTypes(region, eniLimitMap) + describeInstanceTypes(ctx, cfg, region, eniLimitMap) } // Override faulty values and add missing instance types @@ -102,20 +113,14 @@ func main() { // Helper function to call the EC2 DescribeRegions API, returning sorted region names // Note that the credentials being used may not be opted-in to all regions -func describeRegions() []string { - // Get session - sess := session.Must(session.NewSessionWithOptions(session.Options{ - SharedConfigState: session.SharedConfigEnable, - })) - _, err := sess.Config.Credentials.Get() - if err != nil { - log.Fatalf("Failed to get session credentials: %v", err) - } - svc := ec2.New(sess) - output, err := svc.DescribeRegions(&ec2.DescribeRegionsInput{}) +func describeRegions(ctx context.Context, cfg aws.Config) []string { + client := ec2.NewFromConfig(cfg) + + output, err := client.DescribeRegions(ctx, &ec2.DescribeRegionsInput{}) if err != nil { log.Fatalf("Failed to call EC2 DescribeRegions: %v", err) } + var regionNames []string for _, region := range output.Regions { regionNames = append(regionNames, *region.RegionName) @@ -125,54 +130,61 @@ func describeRegions() []string { } // Helper function to call the EC2 DescribeInstanceTypes API for a region and merge the respective instance-type limits into eniLimitMap -func describeInstanceTypes(region string, eniLimitMap map[string]vpc.InstanceTypeLimits) { +func describeInstanceTypes(ctx context.Context, cfg aws.Config, region string, eniLimitMap map[string]vpc.InstanceTypeLimits) { log.Infof("Describing instance types in region=%s", region) - // Get session - sess := session.Must(session.NewSessionWithOptions(session.Options{ - SharedConfigState: session.SharedConfigEnable, - Config: *aws.NewConfig().WithRegion(region), - })) - _, err := sess.Config.Credentials.Get() - if err != nil { - log.Fatalf("Failed to get session credentials: %v", err) - } - svc := ec2.New(sess) - describeInstanceTypesInput := &ec2.DescribeInstanceTypesInput{} + cfg.Region = region + client := ec2.NewFromConfig(cfg) - for { - output, err := svc.DescribeInstanceTypes(describeInstanceTypesInput) + paginator := ec2.NewDescribeInstanceTypesPaginator(client, &ec2.DescribeInstanceTypesInput{}) + + // Iterate through all pages + for paginator.HasMorePages() { + output, err := paginator.NextPage(ctx) if err != nil { log.Fatalf("Failed to call EC2 DescribeInstanceTypes: %v", err) } + // We just want the type name, ENI and IP limits for _, info := range output.InstanceTypes { // Ignore any missing values - instanceType := aws.StringValue(info.InstanceType) + instanceType := string(info.InstanceType) + // only one network card is supported, so use the MaximumNetworkInterfaces from the default card if more than one are present var eniLimit int if len(info.NetworkInfo.NetworkCards) > 1 { - eniLimit = int(aws.Int64Value(info.NetworkInfo.NetworkCards[*info.NetworkInfo.DefaultNetworkCardIndex].MaximumNetworkInterfaces)) + eniLimit = int(*info.NetworkInfo.NetworkCards[*info.NetworkInfo.DefaultNetworkCardIndex].MaximumNetworkInterfaces) } else { - eniLimit = int(aws.Int64Value(info.NetworkInfo.MaximumNetworkInterfaces)) + eniLimit = int(*info.NetworkInfo.MaximumNetworkInterfaces) } - ipv4Limit := int(aws.Int64Value(info.NetworkInfo.Ipv4AddressesPerInterface)) - isBareMetalInstance := aws.BoolValue(info.BareMetal) - hypervisorType := aws.StringValue(info.Hypervisor) + + ipv4Limit := int(*info.NetworkInfo.Ipv4AddressesPerInterface) + isBareMetalInstance := *info.BareMetal + hypervisorType := string(info.Hypervisor) if hypervisorType == "" { hypervisorType = "unknown" } - networkCards := make([]vpc.NetworkCard, aws.Int64Value(info.NetworkInfo.MaximumNetworkCards)) - defaultNetworkCardIndex := int(aws.Int64Value(info.NetworkInfo.DefaultNetworkCardIndex)) - for idx := 0; idx < len(networkCards); idx += 1 { + + networkCards := make([]vpc.NetworkCard, *info.NetworkInfo.MaximumNetworkCards) + defaultNetworkCardIndex := int(*info.NetworkInfo.DefaultNetworkCardIndex) + + for idx := 0; idx < len(networkCards); idx++ { networkCards[idx] = vpc.NetworkCard{ - MaximumNetworkInterfaces: *info.NetworkInfo.NetworkCards[idx].MaximumNetworkInterfaces, - NetworkCardIndex: *info.NetworkInfo.NetworkCards[idx].NetworkCardIndex, + MaximumNetworkInterfaces: int64(*info.NetworkInfo.NetworkCards[idx].MaximumNetworkInterfaces), + NetworkCardIndex: int64(*info.NetworkInfo.NetworkCards[idx].NetworkCardIndex), } } + if instanceType != "" && eniLimit > 0 && ipv4Limit > 0 { - limits := vpc.InstanceTypeLimits{ENILimit: eniLimit, IPv4Limit: ipv4Limit, NetworkCards: networkCards, HypervisorType: strconv.Quote(hypervisorType), - IsBareMetal: isBareMetalInstance, DefaultNetworkCardIndex: defaultNetworkCardIndex} + limits := vpc.InstanceTypeLimits{ + ENILimit: eniLimit, + IPv4Limit: ipv4Limit, + NetworkCards: networkCards, + HypervisorType: strconv.Quote(hypervisorType), + IsBareMetal: isBareMetalInstance, + DefaultNetworkCardIndex: defaultNetworkCardIndex, + } + if existingLimits, contains := eniLimitMap[instanceType]; contains && !reflect.DeepEqual(existingLimits, limits) { // this should never happen log.Fatalf("A previous region has different limits for instanceType=%s than region=%s", instanceType, region) @@ -180,13 +192,6 @@ func describeInstanceTypes(region string, eniLimitMap map[string]vpc.InstanceTyp eniLimitMap[instanceType] = limits } } - // Paginate to the next request - if output.NextToken == nil { - break - } - describeInstanceTypesInput = &ec2.DescribeInstanceTypesInput{ - NextToken: output.NextToken, - } } } diff --git a/test/framework/framework.go b/test/framework/framework.go index d114e101f1..4f325d94ef 100644 --- a/test/framework/framework.go +++ b/test/framework/framework.go @@ -99,10 +99,16 @@ func New(options Options) *Framework { cloudConfig := aws.CloudConfig{Region: options.AWSRegion, VpcID: options.AWSVPCID, EKSEndpoint: options.EKSEndpoint} + awsCloud, err := aws.NewCloud(cloudConfig) + + if err != nil { + log.Fatalf("failed to create AWS cloud client: %v", err) + } + return &Framework{ Options: options, K8sClient: k8sClient, - CloudServices: aws.NewCloud(cloudConfig), + CloudServices: awsCloud, K8sResourceManagers: k8s.NewResourceManager(k8sClient, clientset, k8sSchema, config), InstallationManager: controller.NewDefaultInstallationManager( helm.NewDefaultReleaseManager(options.KubeConfig)), diff --git a/test/framework/resources/aws/cloud.go b/test/framework/resources/aws/cloud.go index 85a86151b6..fc83bcd005 100644 --- a/test/framework/resources/aws/cloud.go +++ b/test/framework/resources/aws/cloud.go @@ -14,9 +14,11 @@ package aws import ( + "context" + "fmt" + "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/aws/services" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + awsconfig "github.com/aws/aws-sdk-go-v2/config" ) type CloudConfig struct { @@ -44,19 +46,29 @@ type defaultCloud struct { cloudWatch services.CloudWatch } -func NewCloud(config CloudConfig) Cloud { - session := session.Must(session.NewSession(&aws.Config{ - Region: aws.String(config.Region)})) +func NewCloud(config CloudConfig) (Cloud, error) { + + cfg, err := awsconfig.LoadDefaultConfig(context.TODO(), awsconfig.WithRegion(config.Region)) + + if err != nil { + return nil, fmt.Errorf("unable to load SDK config, %v", err) + } + + eksService, err := services.NewEKS(cfg, config.EKSEndpoint) + + if err != nil { + return nil, fmt.Errorf("unable to create EKS service client, %v", err) + } return &defaultCloud{ cfg: config, - ec2: services.NewEC2(session), - iam: services.NewIAM(session), - eks: services.NewEKS(session, config.EKSEndpoint), - autoScaling: services.NewAutoScaling(session), - cloudFormation: services.NewCloudFormation(session), - cloudWatch: services.NewCloudWatch(session), - } + ec2: services.NewEC2(cfg), + iam: services.NewIAM(cfg), + eks: eksService, + autoScaling: services.NewAutoScaling(cfg), + cloudFormation: services.NewCloudFormation(cfg), + cloudWatch: services.NewCloudWatch(cfg), + }, nil } func (c *defaultCloud) EC2() services.EC2 { diff --git a/test/framework/resources/aws/services/autoscaling.go b/test/framework/resources/aws/services/autoscaling.go index 07042a0bfa..d1bc534971 100644 --- a/test/framework/resources/aws/services/autoscaling.go +++ b/test/framework/resources/aws/services/autoscaling.go @@ -14,33 +14,34 @@ package services import ( + "context" "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/autoscaling" - "github.com/aws/aws-sdk-go/service/autoscaling/autoscalingiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/autoscaling" + "github.com/aws/aws-sdk-go-v2/service/autoscaling/types" ) type AutoScaling interface { - DescribeAutoScalingGroup(autoScalingGroupName string) ([]*autoscaling.Group, error) + DescribeAutoScalingGroup(ctx context.Context, autoScalingGroupName string) ([]types.AutoScalingGroup, error) } +// Directly using the client to interact with the service instead of an interface. type defaultAutoScaling struct { - autoscalingiface.AutoScalingAPI + client *autoscaling.Client } -func NewAutoScaling(session *session.Session) AutoScaling { +func NewAutoScaling(cfg aws.Config) AutoScaling { return &defaultAutoScaling{ - AutoScalingAPI: autoscaling.New(session), + client: autoscaling.NewFromConfig(cfg), } } -func (d defaultAutoScaling) DescribeAutoScalingGroup(autoScalingGroupName string) ([]*autoscaling.Group, error) { +func (d defaultAutoScaling) DescribeAutoScalingGroup(ctx context.Context, autoScalingGroupName string) ([]types.AutoScalingGroup, error) { describeAutoScalingGroupIp := &autoscaling.DescribeAutoScalingGroupsInput{ - AutoScalingGroupNames: aws.StringSlice([]string{autoScalingGroupName}), + AutoScalingGroupNames: []string{autoScalingGroupName}, } - asg, err := d.AutoScalingAPI.DescribeAutoScalingGroups(describeAutoScalingGroupIp) + asg, err := d.client.DescribeAutoScalingGroups(ctx, describeAutoScalingGroupIp) if err != nil { return nil, err } diff --git a/test/framework/resources/aws/services/cloudformation.go b/test/framework/resources/aws/services/cloudformation.go index dac5f13e54..20e206a47a 100644 --- a/test/framework/resources/aws/services/cloudformation.go +++ b/test/framework/resources/aws/services/cloudformation.go @@ -18,38 +18,37 @@ import ( "fmt" "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" - "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "k8s.io/apimachinery/pkg/util/wait" ) type CloudFormation interface { - WaitTillStackCreated(stackName string, stackParams []*cloudformation.Parameter, templateBody string) (*cloudformation.DescribeStacksOutput, error) - WaitTillStackDeleted(stackName string) error + WaitTillStackCreated(ctx context.Context, stackName string, stackParams []types.Parameter, templateBody string) (*cloudformation.DescribeStacksOutput, error) + WaitTillStackDeleted(ctx context.Context, stackName string) error } +// Directly using the client instead of the Interface. type defaultCloudFormation struct { - cloudformationiface.CloudFormationAPI + client *cloudformation.Client } -func NewCloudFormation(session *session.Session) CloudFormation { +func NewCloudFormation(cfg aws.Config) CloudFormation { return &defaultCloudFormation{ - CloudFormationAPI: cloudformation.New(session), + client: cloudformation.NewFromConfig(cfg), } } -func (d *defaultCloudFormation) WaitTillStackCreated(stackName string, stackParams []*cloudformation.Parameter, templateBody string) (*cloudformation.DescribeStacksOutput, error) { +func (d *defaultCloudFormation) WaitTillStackCreated(ctx context.Context, stackName string, stackParams []types.Parameter, templateBody string) (*cloudformation.DescribeStacksOutput, error) { createStackInput := &cloudformation.CreateStackInput{ Parameters: stackParams, StackName: aws.String(stackName), TemplateBody: aws.String(templateBody), - Capabilities: aws.StringSlice([]string{cloudformation.CapabilityCapabilityIam}), + Capabilities: []types.Capability{types.CapabilityCapabilityIam}, } - _, err := d.CloudFormationAPI.CreateStack(createStackInput) + _, err := d.client.CreateStack(ctx, createStackInput) if err != nil { return nil, err } @@ -59,25 +58,26 @@ func (d *defaultCloudFormation) WaitTillStackCreated(stackName string, stackPara } var describeStackOutput *cloudformation.DescribeStacksOutput + // Using the provided ctx, ctx.Done() allows wait.PollImmediateUtil to cancel err = wait.PollImmediateUntil(utils.PollIntervalLong, func() (done bool, err error) { - describeStackOutput, err = d.CloudFormationAPI.DescribeStacks(describeStackInput) + describeStackOutput, err = d.client.DescribeStacks(ctx, describeStackInput) if err != nil { return true, err } - if *describeStackOutput.Stacks[0].StackStatus == "CREATE_COMPLETE" { + if describeStackOutput.Stacks[0].StackStatus == types.StackStatusCreateComplete { return true, nil } return false, nil - }, context.Background().Done()) + }, ctx.Done()) return describeStackOutput, err } -func (d *defaultCloudFormation) WaitTillStackDeleted(stackName string) error { +func (d *defaultCloudFormation) WaitTillStackDeleted(ctx context.Context, stackName string) error { deleteStackInput := &cloudformation.DeleteStackInput{ StackName: aws.String(stackName), } - _, err := d.CloudFormationAPI.DeleteStack(deleteStackInput) + _, err := d.client.DeleteStack(ctx, deleteStackInput) if err != nil { return fmt.Errorf("failed to delete stack %s: %v", stackName, err) } @@ -87,16 +87,17 @@ func (d *defaultCloudFormation) WaitTillStackDeleted(stackName string) error { } var describeStackOutput *cloudformation.DescribeStacksOutput + // Using the provided ctx, ctx.Done() allows wait.PollImmediateUtil to cancel if required. err = wait.PollImmediateUntil(utils.PollIntervalLong, func() (done bool, err error) { - describeStackOutput, err = d.CloudFormationAPI.DescribeStacks(describeStackInput) + describeStackOutput, err = d.client.DescribeStacks(ctx, describeStackInput) if err != nil { return true, err } - if *describeStackOutput.Stacks[0].StackStatus == "DELETE_COMPLETE" { + if describeStackOutput.Stacks[0].StackStatus == types.StackStatusDeleteComplete { return true, nil } return false, nil - }, context.Background().Done()) + }, ctx.Done()) return nil } diff --git a/test/framework/resources/aws/services/cloudwatch.go b/test/framework/resources/aws/services/cloudwatch.go index 9680ad1bb4..20efb1bb06 100644 --- a/test/framework/resources/aws/services/cloudwatch.go +++ b/test/framework/resources/aws/services/cloudwatch.go @@ -14,30 +14,31 @@ package services import ( - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" + "context" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudwatch" ) type CloudWatch interface { - GetMetricStatistics(getMetricStatisticsInput *cloudwatch.GetMetricStatisticsInput) (*cloudwatch.GetMetricStatisticsOutput, error) - PutMetricData(input *cloudwatch.PutMetricDataInput) (*cloudwatch.PutMetricDataOutput, error) + GetMetricStatistics(ctx context.Context, params *cloudwatch.GetMetricStatisticsInput, optFns ...func(*cloudwatch.Options)) (*cloudwatch.GetMetricStatisticsOutput, error) + PutMetricData(ctx context.Context, params *cloudwatch.PutMetricDataInput, optFns ...func(*cloudwatch.Options)) (*cloudwatch.PutMetricDataOutput, error) } type defaultCloudWatch struct { - cloudwatchiface.CloudWatchAPI + client *cloudwatch.Client } -func NewCloudWatch(session *session.Session) CloudWatch { +func NewCloudWatch(cfg aws.Config) CloudWatch { return &defaultCloudWatch{ - CloudWatchAPI: cloudwatch.New(session), + client: cloudwatch.NewFromConfig(cfg), } } -func (d *defaultCloudWatch) GetMetricStatistics(getMetricStatisticsInput *cloudwatch.GetMetricStatisticsInput) (*cloudwatch.GetMetricStatisticsOutput, error) { - return d.CloudWatchAPI.GetMetricStatistics(getMetricStatisticsInput) +func (d *defaultCloudWatch) GetMetricStatistics(ctx context.Context, params *cloudwatch.GetMetricStatisticsInput, optFns ...func(*cloudwatch.Options)) (*cloudwatch.GetMetricStatisticsOutput, error) { + return d.client.GetMetricStatistics(ctx, params, optFns...) } -func (d *defaultCloudWatch) PutMetricData(input *cloudwatch.PutMetricDataInput) (*cloudwatch.PutMetricDataOutput, error) { - return d.CloudWatchAPI.PutMetricData(input) +func (d *defaultCloudWatch) PutMetricData(ctx context.Context, params *cloudwatch.PutMetricDataInput, optFns ...func(*cloudwatch.Options)) (*cloudwatch.PutMetricDataOutput, error) { + return d.client.PutMetricData(ctx, params, optFns...) } diff --git a/test/framework/resources/aws/services/ec2.go b/test/framework/resources/aws/services/ec2.go index af5305ba04..b0d3ed8373 100644 --- a/test/framework/resources/aws/services/ec2.go +++ b/test/framework/resources/aws/services/ec2.go @@ -14,53 +14,54 @@ package services import ( + "context" "fmt" "strings" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" ) type EC2 interface { - DescribeInstanceType(instanceType string) ([]*ec2.InstanceTypeInfo, error) - DescribeInstance(instanceID string) (*ec2.Instance, error) - DescribeVPC(vpcID string) (*ec2.DescribeVpcsOutput, error) - DescribeNetworkInterface(interfaceIDs []string) (*ec2.DescribeNetworkInterfacesOutput, error) - AuthorizeSecurityGroupIngress(groupID string, protocol string, fromPort int, toPort int, cidrIP string, sourceSG bool) error - RevokeSecurityGroupIngress(groupID string, protocol string, fromPort int, toPort int, cidrIP string, sourceSG bool) error - AuthorizeSecurityGroupEgress(groupID string, protocol string, fromPort int, toPort int, cidrIP string) error - RevokeSecurityGroupEgress(groupID string, protocol string, fromPort int, toPort int, cidrIP string) error - AssociateVPCCIDRBlock(vpcId string, cidrBlock string) (*ec2.AssociateVpcCidrBlockOutput, error) - TerminateInstance(instanceIDs []string) error - DisAssociateVPCCIDRBlock(associationID string) error - DescribeSubnet(subnetID string) (*ec2.DescribeSubnetsOutput, error) - CreateSubnet(cidrBlock string, vpcID string, az string) (*ec2.CreateSubnetOutput, error) - DeleteSubnet(subnetID string) error - DescribeRouteTables(subnetID string) (*ec2.DescribeRouteTablesOutput, error) - DescribeRouteTablesWithVPCID(vpcID string) (*ec2.DescribeRouteTablesOutput, error) - CreateSecurityGroup(groupName string, description string, vpcID string) (*ec2.CreateSecurityGroupOutput, error) - DeleteSecurityGroup(groupID string) error - AssociateRouteTableToSubnet(routeTableId string, subnetID string) error - CreateKey(keyName string) (*ec2.CreateKeyPairOutput, error) - DeleteKey(keyName string) error - DescribeKey(keyName string) (*ec2.DescribeKeyPairsOutput, error) - ModifyNetworkInterfaceSecurityGroups(securityGroupIds []*string, networkInterfaceId *string) (*ec2.ModifyNetworkInterfaceAttributeOutput, error) - DescribeAvailabilityZones() (*ec2.DescribeAvailabilityZonesOutput, error) - CreateTags(resourceIds []string, tags []*ec2.Tag) (*ec2.CreateTagsOutput, error) - DeleteTags(resourceIds []string, tags []*ec2.Tag) (*ec2.DeleteTagsOutput, error) + DescribeInstanceType(ctx context.Context, instanceType string) ([]types.InstanceTypeInfo, error) + DescribeInstance(ctx context.Context, instanceID string) (types.Instance, error) + DescribeVPC(ctx context.Context, vpcID string) (*ec2.DescribeVpcsOutput, error) + DescribeNetworkInterface(ctx context.Context, interfaceIDs []string) (*ec2.DescribeNetworkInterfacesOutput, error) + AuthorizeSecurityGroupIngress(ctx context.Context, groupID string, protocol string, fromPort int, toPort int, cidrIP string, sourceSG bool) error + RevokeSecurityGroupIngress(ctx context.Context, groupID string, protocol string, fromPort int, toPort int, cidrIP string, sourceSG bool) error + AuthorizeSecurityGroupEgress(ctx context.Context, groupID string, protocol string, fromPort int, toPort int, cidrIP string) error + RevokeSecurityGroupEgress(ctx context.Context, groupID string, protocol string, fromPort int, toPort int, cidrIP string) error + AssociateVPCCIDRBlock(ctx context.Context, vpcId string, cidrBlock string) (*ec2.AssociateVpcCidrBlockOutput, error) + TerminateInstance(ctx context.Context, instanceIDs []string) error + DisAssociateVPCCIDRBlock(ctx context.Context, associationID string) error + DescribeSubnet(ctx context.Context, subnetID string) (*ec2.DescribeSubnetsOutput, error) + CreateSubnet(ctx context.Context, cidrBlock string, vpcID string, az string) (*ec2.CreateSubnetOutput, error) + DeleteSubnet(ctx context.Context, subnetID string) error + DescribeRouteTables(ctx context.Context, subnetID string) (*ec2.DescribeRouteTablesOutput, error) + DescribeRouteTablesWithVPCID(ctx context.Context, vpcID string) (*ec2.DescribeRouteTablesOutput, error) + CreateSecurityGroup(ctx context.Context, groupName string, description string, vpcID string) (*ec2.CreateSecurityGroupOutput, error) + DeleteSecurityGroup(ctx context.Context, groupID string) error + AssociateRouteTableToSubnet(ctx context.Context, routeTableId string, subnetID string) error + CreateKey(ctx context.Context, keyName string) (*ec2.CreateKeyPairOutput, error) + DeleteKey(ctx context.Context, keyName string) error + DescribeKey(ctx context.Context, keyName string) (*ec2.DescribeKeyPairsOutput, error) + ModifyNetworkInterfaceSecurityGroups(ctx context.Context, securityGroupIds []string, networkInterfaceId *string) (*ec2.ModifyNetworkInterfaceAttributeOutput, error) + DescribeAvailabilityZones(ctx context.Context) (*ec2.DescribeAvailabilityZonesOutput, error) + CreateTags(ctx context.Context, resourceIds []string, tags []types.Tag) (*ec2.CreateTagsOutput, error) + DeleteTags(ctx context.Context, resourceIds []string, tags []types.Tag) (*ec2.DeleteTagsOutput, error) } type defaultEC2 struct { - ec2iface.EC2API + client *ec2.Client } -func (d *defaultEC2) DescribeInstanceType(instanceType string) ([]*ec2.InstanceTypeInfo, error) { +func (d *defaultEC2) DescribeInstanceType(ctx context.Context, instanceType string) ([]types.InstanceTypeInfo, error) { describeInstanceTypeIp := &ec2.DescribeInstanceTypesInput{ - InstanceTypes: aws.StringSlice([]string{instanceType}), + InstanceTypes: []types.InstanceType{types.InstanceType(instanceType)}, } - describeInstanceOp, err := d.EC2API.DescribeInstanceTypes(describeInstanceTypeIp) + describeInstanceOp, err := d.client.DescribeInstanceTypes(ctx, describeInstanceTypeIp) if err != nil { return nil, err } @@ -70,65 +71,66 @@ func (d *defaultEC2) DescribeInstanceType(instanceType string) ([]*ec2.InstanceT return describeInstanceOp.InstanceTypes, nil } -func (d *defaultEC2) DescribeAvailabilityZones() (*ec2.DescribeAvailabilityZonesOutput, error) { +func (d *defaultEC2) DescribeAvailabilityZones(ctx context.Context) (*ec2.DescribeAvailabilityZonesOutput, error) { describeAvailabilityZonesInput := &ec2.DescribeAvailabilityZonesInput{} - return d.EC2API.DescribeAvailabilityZones(describeAvailabilityZonesInput) + return d.client.DescribeAvailabilityZones(ctx, describeAvailabilityZonesInput) } -func (d *defaultEC2) ModifyNetworkInterfaceSecurityGroups(securityGroupIds []*string, networkInterfaceId *string) (*ec2.ModifyNetworkInterfaceAttributeOutput, error) { - return d.EC2API.ModifyNetworkInterfaceAttribute(&ec2.ModifyNetworkInterfaceAttributeInput{ +func (d *defaultEC2) ModifyNetworkInterfaceSecurityGroups(ctx context.Context, securityGroupIds []string, networkInterfaceId *string) (*ec2.ModifyNetworkInterfaceAttributeOutput, error) { + return d.client.ModifyNetworkInterfaceAttribute(ctx, &ec2.ModifyNetworkInterfaceAttributeInput{ NetworkInterfaceId: networkInterfaceId, Groups: securityGroupIds, }) } -func (d *defaultEC2) DescribeInstance(instanceID string) (*ec2.Instance, error) { +func (d *defaultEC2) DescribeInstance(ctx context.Context, instanceID string) (types.Instance, error) { describeInstanceInput := &ec2.DescribeInstancesInput{ - InstanceIds: aws.StringSlice([]string{instanceID}), + InstanceIds: []string{instanceID}, } - describeInstanceOutput, err := d.EC2API.DescribeInstances(describeInstanceInput) + describeInstanceOutput, err := d.client.DescribeInstances(ctx, describeInstanceInput) + if err != nil { - return nil, err + return types.Instance{}, err } if describeInstanceOutput == nil || len(describeInstanceOutput.Reservations) == 0 || len(describeInstanceOutput.Reservations[0].Instances) == 0 { - return nil, fmt.Errorf("failed to find instance %s", instanceID) + return types.Instance{}, fmt.Errorf("failed to find instance %s", instanceID) } return describeInstanceOutput.Reservations[0].Instances[0], nil } -func (d *defaultEC2) AuthorizeSecurityGroupIngress(groupID string, protocol string, fromPort int, toPort int, cidrIP string, sourceSG bool) error { - var ipv4Ranges []*ec2.IpRange - var ipv6Ranges []*ec2.Ipv6Range - var ipPermissions *ec2.IpPermission +func (d *defaultEC2) AuthorizeSecurityGroupIngress(ctx context.Context, groupID string, protocol string, fromPort int, toPort int, cidrIP string, sourceSG bool) error { + var ipv4Ranges []types.IpRange + var ipv6Ranges []types.Ipv6Range + var ipPermissions types.IpPermission if !sourceSG { if strings.Contains(cidrIP, ":") { - ipv6Ranges = []*ec2.Ipv6Range{ + ipv6Ranges = []types.Ipv6Range{ { CidrIpv6: aws.String(cidrIP), }, } } else { - ipv4Ranges = []*ec2.IpRange{ + ipv4Ranges = []types.IpRange{ { CidrIp: aws.String(cidrIP), }, } } - ipPermissions = &ec2.IpPermission{ - FromPort: aws.Int64(int64(fromPort)), - ToPort: aws.Int64(int64(toPort)), + ipPermissions = types.IpPermission{ + FromPort: aws.Int32(int32(fromPort)), + ToPort: aws.Int32(int32(toPort)), IpProtocol: aws.String(protocol), IpRanges: ipv4Ranges, Ipv6Ranges: ipv6Ranges, } } else { - ipPermissions = &ec2.IpPermission{ - FromPort: aws.Int64(int64(fromPort)), - ToPort: aws.Int64(int64(toPort)), + ipPermissions = types.IpPermission{ + FromPort: aws.Int32(int32(fromPort)), + ToPort: aws.Int32(int32(toPort)), IpProtocol: aws.String(protocol), - UserIdGroupPairs: []*ec2.UserIdGroupPair{ + UserIdGroupPairs: []types.UserIdGroupPair{ { GroupId: aws.String(cidrIP), }, @@ -137,44 +139,44 @@ func (d *defaultEC2) AuthorizeSecurityGroupIngress(groupID string, protocol stri } authorizeSecurityGroupIngressInput := &ec2.AuthorizeSecurityGroupIngressInput{ GroupId: aws.String(groupID), - IpPermissions: []*ec2.IpPermission{ipPermissions}, + IpPermissions: []types.IpPermission{ipPermissions}, } - _, err := d.EC2API.AuthorizeSecurityGroupIngress(authorizeSecurityGroupIngressInput) + _, err := d.client.AuthorizeSecurityGroupIngress(ctx, authorizeSecurityGroupIngressInput) return err } -func (d *defaultEC2) RevokeSecurityGroupIngress(groupID string, protocol string, fromPort int, toPort int, cidrIP string, sourceSG bool) error { - var ipv4Ranges []*ec2.IpRange - var ipv6Ranges []*ec2.Ipv6Range - var ipPermissions *ec2.IpPermission +func (d *defaultEC2) RevokeSecurityGroupIngress(ctx context.Context, groupID string, protocol string, fromPort int, toPort int, cidrIP string, sourceSG bool) error { + var ipv4Ranges []types.IpRange + var ipv6Ranges []types.Ipv6Range + var ipPermissions types.IpPermission if !sourceSG { if strings.Contains(cidrIP, ":") { - ipv6Ranges = []*ec2.Ipv6Range{ + ipv6Ranges = []types.Ipv6Range{ { CidrIpv6: aws.String(cidrIP), }, } } else { - ipv4Ranges = []*ec2.IpRange{ + ipv4Ranges = []types.IpRange{ { CidrIp: aws.String(cidrIP), }, } } - ipPermissions = &ec2.IpPermission{ - FromPort: aws.Int64(int64(fromPort)), - ToPort: aws.Int64(int64(toPort)), + ipPermissions = types.IpPermission{ + FromPort: aws.Int32(int32(fromPort)), + ToPort: aws.Int32(int32(toPort)), IpProtocol: aws.String(protocol), IpRanges: ipv4Ranges, Ipv6Ranges: ipv6Ranges, } } else { - ipPermissions = &ec2.IpPermission{ - FromPort: aws.Int64(int64(fromPort)), - ToPort: aws.Int64(int64(toPort)), + ipPermissions = types.IpPermission{ + FromPort: aws.Int32(int32(fromPort)), + ToPort: aws.Int32(int32(toPort)), IpProtocol: aws.String(protocol), - UserIdGroupPairs: []*ec2.UserIdGroupPair{ + UserIdGroupPairs: []types.UserIdGroupPair{ { GroupId: aws.String(cidrIP), }, @@ -183,236 +185,236 @@ func (d *defaultEC2) RevokeSecurityGroupIngress(groupID string, protocol string, } revokeSecurityGroupIngressInput := &ec2.RevokeSecurityGroupIngressInput{ GroupId: aws.String(groupID), - IpPermissions: []*ec2.IpPermission{ipPermissions}, + IpPermissions: []types.IpPermission{ipPermissions}, } - _, err := d.EC2API.RevokeSecurityGroupIngress(revokeSecurityGroupIngressInput) + _, err := d.client.RevokeSecurityGroupIngress(ctx, revokeSecurityGroupIngressInput) return err } -func (d *defaultEC2) AuthorizeSecurityGroupEgress(groupID string, protocol string, fromPort int, toPort int, cidrIP string) error { - var ipv4Ranges []*ec2.IpRange - var ipv6Ranges []*ec2.Ipv6Range +func (d *defaultEC2) AuthorizeSecurityGroupEgress(ctx context.Context, groupID string, protocol string, fromPort int, toPort int, cidrIP string) error { + var ipv4Ranges []types.IpRange + var ipv6Ranges []types.Ipv6Range if strings.Contains(cidrIP, ":") { - ipv6Ranges = []*ec2.Ipv6Range{ + ipv6Ranges = []types.Ipv6Range{ { CidrIpv6: aws.String(cidrIP), }, } } else { - ipv4Ranges = []*ec2.IpRange{ + ipv4Ranges = []types.IpRange{ { CidrIp: aws.String(cidrIP), }, } } - ipPermissions := &ec2.IpPermission{ - FromPort: aws.Int64(int64(fromPort)), - ToPort: aws.Int64(int64(toPort)), + ipPermissions := types.IpPermission{ + FromPort: aws.Int32(int32(fromPort)), + ToPort: aws.Int32(int32(toPort)), IpProtocol: aws.String(protocol), IpRanges: ipv4Ranges, Ipv6Ranges: ipv6Ranges, } authorizeSecurityGroupEgressInput := &ec2.AuthorizeSecurityGroupEgressInput{ GroupId: aws.String(groupID), - IpPermissions: []*ec2.IpPermission{ipPermissions}, + IpPermissions: []types.IpPermission{ipPermissions}, } - _, err := d.EC2API.AuthorizeSecurityGroupEgress(authorizeSecurityGroupEgressInput) + _, err := d.client.AuthorizeSecurityGroupEgress(ctx, authorizeSecurityGroupEgressInput) return err } -func (d *defaultEC2) RevokeSecurityGroupEgress(groupID string, protocol string, fromPort int, toPort int, cidrIP string) error { - var ipv4Ranges []*ec2.IpRange - var ipv6Ranges []*ec2.Ipv6Range +func (d *defaultEC2) RevokeSecurityGroupEgress(ctx context.Context, groupID string, protocol string, fromPort int, toPort int, cidrIP string) error { + var ipv4Ranges []types.IpRange + var ipv6Ranges []types.Ipv6Range if strings.Contains(cidrIP, ":") { - ipv6Ranges = []*ec2.Ipv6Range{ + ipv6Ranges = []types.Ipv6Range{ { CidrIpv6: aws.String(cidrIP), }, } } else { - ipv4Ranges = []*ec2.IpRange{ + ipv4Ranges = []types.IpRange{ { CidrIp: aws.String(cidrIP), }, } } - ipPermissions := &ec2.IpPermission{ - FromPort: aws.Int64(int64(fromPort)), - ToPort: aws.Int64(int64(toPort)), + ipPermissions := types.IpPermission{ + FromPort: aws.Int32(int32(fromPort)), + ToPort: aws.Int32(int32(toPort)), IpProtocol: aws.String(protocol), IpRanges: ipv4Ranges, Ipv6Ranges: ipv6Ranges, } revokeSecurityGroupEgressInput := &ec2.RevokeSecurityGroupEgressInput{ GroupId: aws.String(groupID), - IpPermissions: []*ec2.IpPermission{ipPermissions}, + IpPermissions: []types.IpPermission{ipPermissions}, } - _, err := d.EC2API.RevokeSecurityGroupEgress(revokeSecurityGroupEgressInput) + _, err := d.client.RevokeSecurityGroupEgress(ctx, revokeSecurityGroupEgressInput) return err } -func (d *defaultEC2) DescribeNetworkInterface(interfaceIDs []string) (*ec2.DescribeNetworkInterfacesOutput, error) { +func (d *defaultEC2) DescribeNetworkInterface(ctx context.Context, interfaceIDs []string) (*ec2.DescribeNetworkInterfacesOutput, error) { describeNetworkInterfaceInput := &ec2.DescribeNetworkInterfacesInput{ - NetworkInterfaceIds: aws.StringSlice(interfaceIDs), + NetworkInterfaceIds: interfaceIDs, } - return d.EC2API.DescribeNetworkInterfaces(describeNetworkInterfaceInput) + return d.client.DescribeNetworkInterfaces(ctx, describeNetworkInterfaceInput) } -func (d *defaultEC2) AssociateVPCCIDRBlock(vpcId string, cidrBlock string) (*ec2.AssociateVpcCidrBlockOutput, error) { +func (d *defaultEC2) AssociateVPCCIDRBlock(ctx context.Context, vpcId string, cidrBlock string) (*ec2.AssociateVpcCidrBlockOutput, error) { associateVPCCidrBlockInput := &ec2.AssociateVpcCidrBlockInput{ CidrBlock: aws.String(cidrBlock), VpcId: aws.String(vpcId), } - return d.EC2API.AssociateVpcCidrBlock(associateVPCCidrBlockInput) + return d.client.AssociateVpcCidrBlock(ctx, associateVPCCidrBlockInput) } -func (d *defaultEC2) DisAssociateVPCCIDRBlock(associationID string) error { +func (d *defaultEC2) DisAssociateVPCCIDRBlock(ctx context.Context, associationID string) error { disassociateVPCCidrBlockInput := &ec2.DisassociateVpcCidrBlockInput{ AssociationId: aws.String(associationID), } - _, err := d.EC2API.DisassociateVpcCidrBlock(disassociateVPCCidrBlockInput) + _, err := d.client.DisassociateVpcCidrBlock(ctx, disassociateVPCCidrBlockInput) return err } -func (d *defaultEC2) CreateSubnet(cidrBlock string, vpcID string, az string) (*ec2.CreateSubnetOutput, error) { +func (d *defaultEC2) CreateSubnet(ctx context.Context, cidrBlock string, vpcID string, az string) (*ec2.CreateSubnetOutput, error) { createSubnetInput := &ec2.CreateSubnetInput{ AvailabilityZone: aws.String(az), CidrBlock: aws.String(cidrBlock), VpcId: aws.String(vpcID), } - return d.EC2API.CreateSubnet(createSubnetInput) + return d.client.CreateSubnet(ctx, createSubnetInput) } -func (d *defaultEC2) DescribeSubnet(subnetID string) (*ec2.DescribeSubnetsOutput, error) { +func (d *defaultEC2) DescribeSubnet(ctx context.Context, subnetID string) (*ec2.DescribeSubnetsOutput, error) { describeSubnetInput := &ec2.DescribeSubnetsInput{ - SubnetIds: aws.StringSlice([]string{subnetID}), + SubnetIds: []string{subnetID}, } - return d.EC2API.DescribeSubnets(describeSubnetInput) + return d.client.DescribeSubnets(ctx, describeSubnetInput) } -func (d *defaultEC2) DescribeRouteTablesWithVPCID(vpcID string) (*ec2.DescribeRouteTablesOutput, error) { +func (d *defaultEC2) DescribeRouteTablesWithVPCID(ctx context.Context, vpcID string) (*ec2.DescribeRouteTablesOutput, error) { describeRouteTableInput := &ec2.DescribeRouteTablesInput{ - Filters: []*ec2.Filter{ + Filters: []types.Filter{ { Name: aws.String("vpc-id"), - Values: aws.StringSlice([]string{vpcID}), + Values: []string{vpcID}, }, }, } - return d.EC2API.DescribeRouteTables(describeRouteTableInput) + return d.client.DescribeRouteTables(ctx, describeRouteTableInput) } -func (d *defaultEC2) DeleteSubnet(subnetID string) error { +func (d *defaultEC2) DeleteSubnet(ctx context.Context, subnetID string) error { deleteSubnetInput := &ec2.DeleteSubnetInput{ SubnetId: aws.String(subnetID), } - _, err := d.EC2API.DeleteSubnet(deleteSubnetInput) + _, err := d.client.DeleteSubnet(ctx, deleteSubnetInput) return err } -func (d *defaultEC2) DescribeRouteTables(subnetID string) (*ec2.DescribeRouteTablesOutput, error) { +func (d *defaultEC2) DescribeRouteTables(ctx context.Context, subnetID string) (*ec2.DescribeRouteTablesOutput, error) { describeRouteTableInput := &ec2.DescribeRouteTablesInput{ - Filters: []*ec2.Filter{ + Filters: []types.Filter{ { Name: aws.String("association.subnet-id"), - Values: aws.StringSlice([]string{subnetID}), + Values: []string{subnetID}, }, }, } - return d.EC2API.DescribeRouteTables(describeRouteTableInput) + return d.client.DescribeRouteTables(ctx, describeRouteTableInput) } -func (d *defaultEC2) AssociateRouteTableToSubnet(routeTableId string, subnetID string) error { +func (d *defaultEC2) AssociateRouteTableToSubnet(ctx context.Context, routeTableId string, subnetID string) error { associateRouteTableInput := &ec2.AssociateRouteTableInput{ RouteTableId: aws.String(routeTableId), SubnetId: aws.String(subnetID), } - _, err := d.EC2API.AssociateRouteTable(associateRouteTableInput) + _, err := d.client.AssociateRouteTable(ctx, associateRouteTableInput) return err } -func (d *defaultEC2) DeleteSecurityGroup(groupID string) error { +func (d *defaultEC2) DeleteSecurityGroup(ctx context.Context, groupID string) error { deleteSecurityGroupInput := &ec2.DeleteSecurityGroupInput{ GroupId: aws.String(groupID), } - _, err := d.EC2API.DeleteSecurityGroup(deleteSecurityGroupInput) + _, err := d.client.DeleteSecurityGroup(ctx, deleteSecurityGroupInput) return err } -func (d *defaultEC2) CreateSecurityGroup(groupName string, description string, vpcID string) (*ec2.CreateSecurityGroupOutput, error) { +func (d *defaultEC2) CreateSecurityGroup(ctx context.Context, groupName string, description string, vpcID string) (*ec2.CreateSecurityGroupOutput, error) { createSecurityGroupInput := &ec2.CreateSecurityGroupInput{ Description: aws.String(description), GroupName: aws.String(groupName), VpcId: aws.String(vpcID), } - return d.EC2API.CreateSecurityGroup(createSecurityGroupInput) + return d.client.CreateSecurityGroup(ctx, createSecurityGroupInput) } -func (d *defaultEC2) CreateKey(keyName string) (*ec2.CreateKeyPairOutput, error) { +func (d *defaultEC2) CreateKey(ctx context.Context, keyName string) (*ec2.CreateKeyPairOutput, error) { createKeyInput := &ec2.CreateKeyPairInput{ KeyName: aws.String(keyName), } - return d.EC2API.CreateKeyPair(createKeyInput) + return d.client.CreateKeyPair(ctx, createKeyInput) } -func (d *defaultEC2) DeleteKey(keyName string) error { +func (d *defaultEC2) DeleteKey(ctx context.Context, keyName string) error { deleteKeyPairInput := &ec2.DeleteKeyPairInput{ KeyName: aws.String(keyName), } - _, err := d.EC2API.DeleteKeyPair(deleteKeyPairInput) + _, err := d.client.DeleteKeyPair(ctx, deleteKeyPairInput) return err } -func (d *defaultEC2) DescribeKey(keyName string) (*ec2.DescribeKeyPairsOutput, error) { +func (d *defaultEC2) DescribeKey(ctx context.Context, keyName string) (*ec2.DescribeKeyPairsOutput, error) { keyPairInput := &ec2.DescribeKeyPairsInput{ - KeyNames: []*string{ - &keyName, + KeyNames: []string{ + keyName, }, } - return d.EC2API.DescribeKeyPairs(keyPairInput) + return d.client.DescribeKeyPairs(ctx, keyPairInput) } -func (d *defaultEC2) TerminateInstance(instanceIDs []string) error { +func (d *defaultEC2) TerminateInstance(ctx context.Context, instanceIDs []string) error { terminateInstanceInput := &ec2.TerminateInstancesInput{ DryRun: nil, - InstanceIds: aws.StringSlice(instanceIDs), + InstanceIds: instanceIDs, } - _, err := d.EC2API.TerminateInstances(terminateInstanceInput) + _, err := d.client.TerminateInstances(ctx, terminateInstanceInput) return err } -func (d *defaultEC2) DescribeVPC(vpcID string) (*ec2.DescribeVpcsOutput, error) { +func (d *defaultEC2) DescribeVPC(ctx context.Context, vpcID string) (*ec2.DescribeVpcsOutput, error) { describeVPCInput := &ec2.DescribeVpcsInput{ - VpcIds: aws.StringSlice([]string{vpcID}), + VpcIds: []string{vpcID}, } - return d.EC2API.DescribeVpcs(describeVPCInput) + return d.client.DescribeVpcs(ctx, describeVPCInput) } -func (d *defaultEC2) CreateTags(resourceIds []string, tags []*ec2.Tag) (*ec2.CreateTagsOutput, error) { +func (d *defaultEC2) CreateTags(ctx context.Context, resourceIds []string, tags []types.Tag) (*ec2.CreateTagsOutput, error) { input := &ec2.CreateTagsInput{ - Resources: aws.StringSlice(resourceIds), + Resources: resourceIds, Tags: tags, } - return d.EC2API.CreateTags(input) + return d.client.CreateTags(ctx, input) } -func (d *defaultEC2) DeleteTags(resourceIds []string, tags []*ec2.Tag) (*ec2.DeleteTagsOutput, error) { +func (d *defaultEC2) DeleteTags(ctx context.Context, resourceIds []string, tags []types.Tag) (*ec2.DeleteTagsOutput, error) { input := &ec2.DeleteTagsInput{ - Resources: aws.StringSlice(resourceIds), + Resources: resourceIds, Tags: tags, } - return d.EC2API.DeleteTags(input) + return d.client.DeleteTags(ctx, input) } -func NewEC2(session *session.Session) EC2 { +func NewEC2(cfg aws.Config) EC2 { return &defaultEC2{ - EC2API: ec2.New(session), + client: ec2.NewFromConfig(cfg), } } diff --git a/test/framework/resources/aws/services/eks.go b/test/framework/resources/aws/services/eks.go index 1b1b35bf64..4b3ed762b5 100644 --- a/test/framework/resources/aws/services/eks.go +++ b/test/framework/resources/aws/services/eks.go @@ -14,23 +14,25 @@ package services import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" + "context" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/eks" + "github.com/aws/aws-sdk-go-v2/service/eks/types" ) type EKS interface { - DescribeCluster(clusterName string) (*eks.DescribeClusterOutput, error) - CreateAddon(addonInput *AddonInput) (*eks.CreateAddonOutput, error) - DescribeAddonVersions(AddonInput *AddonInput) (*eks.DescribeAddonVersionsOutput, error) - DescribeAddon(addonInput *AddonInput) (*eks.DescribeAddonOutput, error) - DeleteAddon(AddOnInput *AddonInput) (*eks.DeleteAddonOutput, error) - GetLatestVersion(addonInput *AddonInput) (string, error) + DescribeCluster(ctx context.Context, clusterName string) (*eks.DescribeClusterOutput, error) + CreateAddon(ctx context.Context, addonInput AddonInput) (*eks.CreateAddonOutput, error) + DescribeAddonVersions(ctx context.Context, addonInput AddonInput) (*eks.DescribeAddonVersionsOutput, error) + DescribeAddon(ctx context.Context, addonInput AddonInput) (*eks.DescribeAddonOutput, error) + DeleteAddon(ctx context.Context, addOnInput AddonInput) (*eks.DeleteAddonOutput, error) + GetLatestVersion(ctx context.Context, addonInput AddonInput) (string, error) } type defaultEKS struct { - eksiface.EKSAPI + client *eks.Client } // Internal Addon Input struct @@ -43,63 +45,81 @@ type AddonInput struct { K8sVersion string } -func NewEKS(session *session.Session, endpoint string) EKS { - return &defaultEKS{ - EKSAPI: eks.New(session, &aws.Config{ - Endpoint: aws.String(endpoint), - Region: session.Config.Region, - }), +func NewEKS(cfg aws.Config, endpoint string) (EKS, error) { + var err error + + if endpoint != "" { + customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) { + return aws.Endpoint{ + URL: endpoint, + }, nil + }) + cfg, err = config.LoadDefaultConfig(context.Background(), + config.WithEndpointResolverWithOptions(customResolver), + config.WithRegion(cfg.Region), + ) + } else { + cfg, err = config.LoadDefaultConfig(context.Background(), + config.WithRegion(cfg.Region), + ) } + + if err != nil { + return &defaultEKS{}, err + } + + return &defaultEKS{ + client: eks.NewFromConfig(cfg), + }, nil } -func (d defaultEKS) CreateAddon(addonInput *AddonInput) (*eks.CreateAddonOutput, error) { +func (d *defaultEKS) CreateAddon(ctx context.Context, addonInput AddonInput) (*eks.CreateAddonOutput, error) { createAddonInput := &eks.CreateAddonInput{ AddonName: aws.String(addonInput.AddonName), ClusterName: aws.String(addonInput.ClusterName), } if addonInput.AddonVersion != "" { - createAddonInput.SetAddonVersion(addonInput.AddonVersion) - createAddonInput.SetResolveConflicts("OVERWRITE") + createAddonInput.AddonVersion = aws.String(addonInput.AddonVersion) + createAddonInput.ResolveConflicts = types.ResolveConflictsOverwrite } - return d.EKSAPI.CreateAddon(createAddonInput) + return d.client.CreateAddon(ctx, createAddonInput) } -func (d defaultEKS) DeleteAddon(addonInput *AddonInput) (*eks.DeleteAddonOutput, error) { +func (d *defaultEKS) DeleteAddon(ctx context.Context, addonInput AddonInput) (*eks.DeleteAddonOutput, error) { deleteAddonInput := &eks.DeleteAddonInput{ AddonName: aws.String(addonInput.AddonName), ClusterName: aws.String(addonInput.ClusterName), } - return d.EKSAPI.DeleteAddon(deleteAddonInput) + return d.client.DeleteAddon(ctx, deleteAddonInput) } -func (d defaultEKS) DescribeAddonVersions(addonInput *AddonInput) (*eks.DescribeAddonVersionsOutput, error) { +func (d *defaultEKS) DescribeAddonVersions(ctx context.Context, addonInput AddonInput) (*eks.DescribeAddonVersionsOutput, error) { describeAddonVersionsInput := &eks.DescribeAddonVersionsInput{ AddonName: aws.String(addonInput.AddonName), KubernetesVersion: aws.String(addonInput.K8sVersion), } - return d.EKSAPI.DescribeAddonVersions(describeAddonVersionsInput) + return d.client.DescribeAddonVersions(ctx, describeAddonVersionsInput) } -func (d defaultEKS) DescribeAddon(addonInput *AddonInput) (*eks.DescribeAddonOutput, error) { +func (d *defaultEKS) DescribeAddon(ctx context.Context, addonInput AddonInput) (*eks.DescribeAddonOutput, error) { describeAddonInput := &eks.DescribeAddonInput{ AddonName: aws.String(addonInput.AddonName), ClusterName: aws.String(addonInput.ClusterName), } - return d.EKSAPI.DescribeAddon(describeAddonInput) + return d.client.DescribeAddon(ctx, describeAddonInput) } -func (d defaultEKS) DescribeCluster(clusterName string) (*eks.DescribeClusterOutput, error) { +func (d *defaultEKS) DescribeCluster(ctx context.Context, clusterName string) (*eks.DescribeClusterOutput, error) { describeClusterInput := &eks.DescribeClusterInput{ Name: aws.String(clusterName), } - - return d.EKSAPI.DescribeCluster(describeClusterInput) + return d.client.DescribeCluster(ctx, describeClusterInput) } -func (d defaultEKS) GetLatestVersion(addonInput *AddonInput) (string, error) { - addonOutput, err := d.DescribeAddonVersions(addonInput) +func (d *defaultEKS) GetLatestVersion(ctx context.Context, addonInput AddonInput) (string, error) { + addonOutput, err := d.DescribeAddonVersions(ctx, addonInput) if err != nil { return "", err } - return *addonOutput.Addons[0].AddonVersions[0].AddonVersion, nil + return aws.ToString(addonOutput.Addons[0].AddonVersions[0].AddonVersion), nil } diff --git a/test/framework/resources/aws/services/iam.go b/test/framework/resources/aws/services/iam.go index 688bbb9d82..779fbf775e 100644 --- a/test/framework/resources/aws/services/iam.go +++ b/test/framework/resources/aws/services/iam.go @@ -14,10 +14,11 @@ package services import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/iam" - "github.com/aws/aws-sdk-go/service/iam/iamiface" + "context" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iam" + "github.com/aws/aws-sdk-go-v2/service/iam/types" ) type PolicyDocument struct { @@ -32,88 +33,88 @@ type StatementEntry struct { } type IAM interface { - AttachRolePolicy(policyArn string, roleName string) error - DetachRolePolicy(policyARN string, roleName string) error - CreatePolicy(policyName string, policyDocument string) (*iam.CreatePolicyOutput, error) - DeletePolicy(policyARN string) error - GetInstanceProfile(instanceProfileName string) (*iam.GetInstanceProfileOutput, error) - GetRolePolicy(policyName string, role string) (*iam.GetRolePolicyOutput, error) - PutRolePolicy(policyDocument string, policyName string, roleName string) error - ListPolicies(scope string) (*iam.ListPoliciesOutput, error) + AttachRolePolicy(ctx context.Context, policyArn string, roleName string) error + DetachRolePolicy(ctx context.Context, policyARN string, roleName string) error + CreatePolicy(ctx context.Context, policyName string, policyDocument string) (*iam.CreatePolicyOutput, error) + DeletePolicy(ctx context.Context, policyARN string) error + GetInstanceProfile(ctx context.Context, instanceProfileName string) (*iam.GetInstanceProfileOutput, error) + GetRolePolicy(ctx context.Context, policyName string, role string) (*iam.GetRolePolicyOutput, error) + PutRolePolicy(ctx context.Context, policyDocument string, policyName string, roleName string) error + ListPolicies(ctx context.Context, scope string) (*iam.ListPoliciesOutput, error) } type defaultIAM struct { - iamiface.IAMAPI + client *iam.Client } -func (d *defaultIAM) AttachRolePolicy(policyARN string, roleName string) error { +func (d *defaultIAM) AttachRolePolicy(ctx context.Context, policyARN string, roleName string) error { attachRolePolicyInput := &iam.AttachRolePolicyInput{ PolicyArn: aws.String(policyARN), RoleName: aws.String(roleName), } - _, err := d.IAMAPI.AttachRolePolicy(attachRolePolicyInput) + _, err := d.client.AttachRolePolicy(ctx, attachRolePolicyInput) return err } -func (d *defaultIAM) DetachRolePolicy(policyARN string, roleName string) error { +func (d *defaultIAM) DetachRolePolicy(ctx context.Context, policyARN string, roleName string) error { detachRolePolicyInput := &iam.DetachRolePolicyInput{ PolicyArn: aws.String(policyARN), RoleName: aws.String(roleName), } - _, err := d.IAMAPI.DetachRolePolicy(detachRolePolicyInput) + _, err := d.client.DetachRolePolicy(ctx, detachRolePolicyInput) return err } -func (d *defaultIAM) CreatePolicy(policyName string, policyDocument string) (*iam.CreatePolicyOutput, error) { +func (d *defaultIAM) CreatePolicy(ctx context.Context, policyName string, policyDocument string) (*iam.CreatePolicyOutput, error) { createPolicyInput := &iam.CreatePolicyInput{ PolicyDocument: aws.String(policyDocument), PolicyName: aws.String(policyName), } - return d.IAMAPI.CreatePolicy(createPolicyInput) + return d.client.CreatePolicy(ctx, createPolicyInput) } -func (d *defaultIAM) DeletePolicy(policyARN string) error { +func (d *defaultIAM) DeletePolicy(ctx context.Context, policyARN string) error { deletePolicyInput := &iam.DeletePolicyInput{ PolicyArn: aws.String(policyARN), } - _, err := d.IAMAPI.DeletePolicy(deletePolicyInput) + _, err := d.client.DeletePolicy(ctx, deletePolicyInput) return err } -func (d *defaultIAM) GetRolePolicy(role string, policyName string) (*iam.GetRolePolicyOutput, error) { +func (d *defaultIAM) GetRolePolicy(ctx context.Context, role string, policyName string) (*iam.GetRolePolicyOutput, error) { rolePolicyInput := &iam.GetRolePolicyInput{ RoleName: aws.String(role), PolicyName: aws.String(policyName), } - return d.IAMAPI.GetRolePolicy(rolePolicyInput) + return d.client.GetRolePolicy(ctx, rolePolicyInput) } -func (d *defaultIAM) PutRolePolicy(policyDocument string, policyName string, roleName string) error { +func (d *defaultIAM) PutRolePolicy(ctx context.Context, policyDocument string, policyName string, roleName string) error { policyInput := &iam.PutRolePolicyInput{ PolicyDocument: aws.String(policyDocument), PolicyName: aws.String(policyName), RoleName: aws.String(roleName), } - _, err := d.IAMAPI.PutRolePolicy(policyInput) + _, err := d.client.PutRolePolicy(ctx, policyInput) return err } -func (d *defaultIAM) GetInstanceProfile(instanceProfileName string) (*iam.GetInstanceProfileOutput, error) { +func (d *defaultIAM) GetInstanceProfile(ctx context.Context, instanceProfileName string) (*iam.GetInstanceProfileOutput, error) { getInstanceProfileInput := &iam.GetInstanceProfileInput{ InstanceProfileName: aws.String(instanceProfileName), } - return d.IAMAPI.GetInstanceProfile(getInstanceProfileInput) + return d.client.GetInstanceProfile(ctx, getInstanceProfileInput) } -func (d *defaultIAM) ListPolicies(scope string) (*iam.ListPoliciesOutput, error) { +func (d *defaultIAM) ListPolicies(ctx context.Context, scope string) (*iam.ListPoliciesOutput, error) { listPolicyInput := &iam.ListPoliciesInput{ - Scope: aws.String(scope), + Scope: types.PolicyScopeType(scope), } - return d.IAMAPI.ListPolicies(listPolicyInput) + return d.client.ListPolicies(ctx, listPolicyInput) } -func NewIAM(session *session.Session) IAM { +func NewIAM(cfg aws.Config) IAM { return &defaultIAM{ - IAMAPI: iam.New(session), + client: iam.NewFromConfig(cfg), } } diff --git a/test/framework/resources/aws/utils/nodegroup.go b/test/framework/resources/aws/utils/nodegroup.go index 6d395d8ca4..6518857b41 100644 --- a/test/framework/resources/aws/utils/nodegroup.go +++ b/test/framework/resources/aws/utils/nodegroup.go @@ -14,6 +14,7 @@ package utils import ( + "context" "fmt" "os" "strconv" @@ -22,18 +23,15 @@ import ( "gopkg.in/yaml.v2" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" - "github.com/aws/amazon-vpc-cni-k8s/pkg/vpc" "github.com/aws/amazon-vpc-cni-k8s/test/framework" k8sUtils "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/utils" "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformationtypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" ) const ( - // Docker will be default, if not specified - CONTAINERD = "containerd" CreateNodeGroupCFNTemplate = "/testdata/amazon-eks-nodegroup.yaml" NodeImageIdSSMParam = "/aws/service/eks/optimized-ami/%s/amazon-linux-2/recommended/image_id" ) @@ -81,7 +79,7 @@ func CreateAndWaitTillSelfManagedNGReady(f *framework.Framework, properties Node } template := string(templateBytes) - describeClusterOutput, err := f.CloudServices.EKS().DescribeCluster(f.Options.ClusterName) + describeClusterOutput, err := f.CloudServices.EKS().DescribeCluster(context.TODO(), f.Options.ClusterName) if err != nil { return fmt.Errorf("failed to describe cluster %s: %v", f.Options.ClusterName, err) } @@ -105,7 +103,7 @@ func CreateAndWaitTillSelfManagedNGReady(f *framework.Framework, properties Node asgSizeString := strconv.Itoa(properties.AsgSize) - createNgStackParams := []*cloudformation.Parameter{ + createNgStackParams := []cloudformationtypes.Parameter{ { ParameterKey: aws.String("ClusterName"), ParameterValue: aws.String(f.Options.ClusterName), @@ -120,7 +118,7 @@ func CreateAndWaitTillSelfManagedNGReady(f *framework.Framework, properties Node }, { ParameterKey: aws.String("ClusterControlPlaneSecurityGroup"), - ParameterValue: describeClusterOutput.Cluster.ResourcesVpcConfig.SecurityGroupIds[0], + ParameterValue: aws.String(describeClusterOutput.Cluster.ResourcesVpcConfig.SecurityGroupIds[0]), }, { ParameterKey: aws.String("NodeGroupName"), @@ -161,14 +159,14 @@ func CreateAndWaitTillSelfManagedNGReady(f *framework.Framework, properties Node } if properties.NodeImageId != "" { - createNgStackParams = append(createNgStackParams, &cloudformation.Parameter{ + createNgStackParams = append(createNgStackParams, cloudformationtypes.Parameter{ ParameterKey: aws.String("NodeImageId"), ParameterValue: aws.String(properties.NodeImageId), }) } describeStackOutput, err := f.CloudServices.CloudFormation(). - WaitTillStackCreated(properties.NodeGroupName, createNgStackParams, template) + WaitTillStackCreated(context.TODO(), properties.NodeGroupName, createNgStackParams, template) if err != nil { return fmt.Errorf("failed to create node group cfn stack: %v", err) } @@ -220,7 +218,7 @@ func CreateAndWaitTillSelfManagedNGReady(f *framework.Framework, properties Node } func DeleteAndWaitTillSelfManagedNGStackDeleted(f *framework.Framework, properties NodeGroupProperties) error { - err := f.CloudServices.CloudFormation().WaitTillStackDeleted(properties.NodeGroupName) + err := f.CloudServices.CloudFormation().WaitTillStackDeleted(context.TODO(), properties.NodeGroupName) if err != nil { return fmt.Errorf("failed to delete node group cfn stack: %v", err) } @@ -257,33 +255,33 @@ func GetClusterVPCConfig(f *framework.Framework) (*ClusterVPCConfig, error) { return nil, fmt.Errorf("partial configuration, if supplying config via flags you need to provide at least public route table ID, public subnet list and availibility zone list") } - describeClusterOutput, err := f.CloudServices.EKS().DescribeCluster(f.Options.ClusterName) + describeClusterOutput, err := f.CloudServices.EKS().DescribeCluster(context.TODO(), f.Options.ClusterName) if err != nil { return nil, fmt.Errorf("failed to describe cluster %s: %v", f.Options.ClusterName, err) } for _, subnet := range describeClusterOutput.Cluster.ResourcesVpcConfig.SubnetIds { - describeRouteOutput, err := f.CloudServices.EC2().DescribeRouteTables(*subnet) + describeRouteOutput, err := f.CloudServices.EC2().DescribeRouteTables(context.TODO(), subnet) if err != nil { - return nil, fmt.Errorf("failed to describe subnet %s: %v", *subnet, err) + return nil, fmt.Errorf("failed to describe subnet %s: %v", subnet, err) } isPublic := false for _, route := range describeRouteOutput.RouteTables[0].Routes { if route.GatewayId != nil && strings.Contains(*route.GatewayId, "igw-") { isPublic = true - clusterConfig.PublicSubnetList = append(clusterConfig.PublicSubnetList, *subnet) + clusterConfig.PublicSubnetList = append(clusterConfig.PublicSubnetList, subnet) clusterConfig.PublicRouteTableID = *describeRouteOutput.RouteTables[0].RouteTableId } } if !isPublic { - clusterConfig.PrivateSubnetList = append(clusterConfig.PrivateSubnetList, *subnet) + clusterConfig.PrivateSubnetList = append(clusterConfig.PrivateSubnetList, subnet) } } uniqueAZ := map[string]bool{} for _, subnet := range clusterConfig.PublicSubnetList { - describeSubnet, err := f.CloudServices.EC2().DescribeSubnet(subnet) + describeSubnet, err := f.CloudServices.EC2().DescribeSubnet(context.TODO(), subnet) if err != nil { return nil, fmt.Errorf("failed to describe the subnet %s: %v", subnet, err) } @@ -308,7 +306,7 @@ func TerminateInstances(f *framework.Framework) error { instanceIDs = append(instanceIDs, k8sUtils.GetInstanceIDFromNode(node)) } - err = f.CloudServices.EC2().TerminateInstance(instanceIDs) + err = f.CloudServices.EC2().TerminateInstance(context.TODO(), instanceIDs) if err != nil { return fmt.Errorf("failed to terminate instances: %v", err) } diff --git a/test/framework/resources/k8s/manifest/daemonset.go b/test/framework/resources/k8s/manifest/daemonset.go index 2d8a9720a9..058fb2feba 100644 --- a/test/framework/resources/k8s/manifest/daemonset.go +++ b/test/framework/resources/k8s/manifest/daemonset.go @@ -15,7 +15,7 @@ package manifest import ( "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/test/framework/resources/k8s/manifest/deployment.go b/test/framework/resources/k8s/manifest/deployment.go index 4034bcacd8..ae2243006c 100644 --- a/test/framework/resources/k8s/manifest/deployment.go +++ b/test/framework/resources/k8s/manifest/deployment.go @@ -16,7 +16,7 @@ package manifest import ( "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/test/framework/resources/k8s/manifest/job.go b/test/framework/resources/k8s/manifest/job.go index 20d06c3817..cb8a0e9272 100644 --- a/test/framework/resources/k8s/manifest/job.go +++ b/test/framework/resources/k8s/manifest/job.go @@ -14,7 +14,7 @@ package manifest import ( - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" batchV1 "k8s.io/api/batch/v1" v1 "k8s.io/api/core/v1" metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/test/framework/resources/k8s/manifest/pod.go b/test/framework/resources/k8s/manifest/pod.go index c19bf3ee1e..dfbab146e9 100644 --- a/test/framework/resources/k8s/manifest/pod.go +++ b/test/framework/resources/k8s/manifest/pod.go @@ -16,7 +16,7 @@ package manifest import ( "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" v1 "k8s.io/api/core/v1" metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/test/framework/resources/k8s/utils/addon.go b/test/framework/resources/k8s/utils/addon.go index 6bd12d590b..cae427aeb8 100644 --- a/test/framework/resources/k8s/utils/addon.go +++ b/test/framework/resources/k8s/utils/addon.go @@ -12,7 +12,7 @@ import ( func WaitTillAddonIsDeleted(eks services.EKS, addonName string, clusterName string) error { ctx := context.Background() return wait.PollImmediateUntil(utils.PollIntervalShort, func() (bool, error) { - _, err := eks.DescribeAddon(&services.AddonInput{ + _, err := eks.DescribeAddon(context.TODO(), services.AddonInput{ AddonName: addonName, ClusterName: clusterName, }) @@ -26,7 +26,7 @@ func WaitTillAddonIsDeleted(eks services.EKS, addonName string, clusterName stri func WaitTillAddonIsActive(eks services.EKS, addonName string, clusterName string) error { ctx := context.Background() return wait.PollImmediateUntil(utils.PollIntervalShort, func() (bool, error) { - describeAddonOutput, err := eks.DescribeAddon(&services.AddonInput{ + describeAddonOutput, err := eks.DescribeAddon(context.TODO(), services.AddonInput{ AddonName: addonName, ClusterName: clusterName, }) @@ -34,7 +34,7 @@ func WaitTillAddonIsActive(eks services.EKS, addonName string, clusterName strin return false, err } - status := *describeAddonOutput.Addon.Status + status := describeAddonOutput.Addon.Status if status == "CREATE_FAILED" || status == "DEGRADED" { return false, errors.Errorf("Create Addon Failed, addon status: %s", status) } diff --git a/test/integration/az-traffic/pod_az_traffic_suite_test.go b/test/integration/az-traffic/pod_az_traffic_suite_test.go index 292bdf5aa2..c088b62cf7 100644 --- a/test/integration/az-traffic/pod_az_traffic_suite_test.go +++ b/test/integration/az-traffic/pod_az_traffic_suite_test.go @@ -33,7 +33,7 @@ var _ = BeforeSuite(func() { f = framework.New(framework.GlobalOptions) By("creating test namespace") - f.K8sResourceManagers.NamespaceManager().CreateNamespace(utils.DefaultTestNamespace) + _ = f.K8sResourceManagers.NamespaceManager().CreateNamespace(utils.DefaultTestNamespace) By(fmt.Sprintf("getting the node with the node label key %s and value %s", f.Options.NgNameLabelKey, f.Options.NgNameLabelVal)) @@ -44,6 +44,6 @@ var _ = BeforeSuite(func() { var _ = AfterSuite(func() { By("deleting test namespace") - f.K8sResourceManagers.NamespaceManager(). + _ = f.K8sResourceManagers.NamespaceManager(). DeleteAndWaitTillNamespaceDeleted(utils.DefaultTestNamespace) }) diff --git a/test/integration/az-traffic/pod_traffic_across_az_test.go b/test/integration/az-traffic/pod_traffic_across_az_test.go index a0d918f8c2..69755cd295 100644 --- a/test/integration/az-traffic/pod_traffic_across_az_test.go +++ b/test/integration/az-traffic/pod_traffic_across_az_test.go @@ -1,11 +1,13 @@ package az_traffic import ( + "context" "fmt" "strconv" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudwatch" + cloudwatchtypes "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" "github.com/aws/amazon-vpc-cni-k8s/test/framework" "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/manifest" @@ -35,7 +37,7 @@ var _ = Describe("[STATIC_CANARY] AZ Node Presence", FlakeAttempts(retries), fun nodes, err := f.K8sResourceManagers.NodeManager().GetNodes(f.Options.NgNameLabelKey, f.Options.NgNameLabelVal) Expect(err).ToNot(HaveOccurred()) - describeAZOutput, err := f.CloudServices.EC2().DescribeAvailabilityZones() + describeAZOutput, err := f.CloudServices.EC2().DescribeAvailabilityZones(context.TODO()) Expect(err).ToNot(HaveOccurred()) for _, az := range describeAZOutput.AvailabilityZones { @@ -166,7 +168,7 @@ func GetAZMappings(nodes coreV1.NodeList) (map[string]coreV1.Pod, map[string]str // Map of AZ name to AZ ID azToazID := make(map[string]string) - describeAZOutput, err := f.CloudServices.EC2().DescribeAvailabilityZones() + describeAZOutput, err := f.CloudServices.EC2().DescribeAvailabilityZones(context.TODO()) // iterate describe AZ output and populate AZ name to AZ ID mapping for _, az := range describeAZOutput.AvailabilityZones { @@ -249,7 +251,7 @@ var _ = Describe("[STATIC_CANARY] API Server Connectivity from AZs", FlakeAttemp Context("While testing API Server Connectivity", func() { It("Should connect to the API Server", func() { - describeClusterOutput, err := f.CloudServices.EKS().DescribeCluster(f.Options.ClusterName) + describeClusterOutput, err := f.CloudServices.EKS().DescribeCluster(context.TODO(), f.Options.ClusterName) Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("Error while Describing the cluster to find APIServer NLB endpoint. %s", f.Options.ClusterName)) APIServerNLBEndpoint := fmt.Sprintf("%s/api", *describeClusterOutput.Cluster.Endpoint) APIServerInternalEndpoint := "https://kubernetes.default.svc/api" @@ -291,12 +293,12 @@ func CheckAPIServerConnectivityFromPods(azToPod map[string]coreV1.Pod, azToazId if f.Options.PublishCWMetrics { putmetricData := cloudwatch.PutMetricDataInput{ Namespace: aws.String(MetricNamespace), - MetricData: []*cloudwatch.MetricDatum{ + MetricData: []cloudwatchtypes.MetricDatum{ { MetricName: aws.String(MetricName), - Unit: aws.String("Count"), + Unit: cloudwatchtypes.StandardUnitCount, Value: aws.Float64(1), - Dimensions: []*cloudwatch.Dimension{ + Dimensions: []cloudwatchtypes.Dimension{ { Name: aws.String("AZID"), Value: aws.String(azToazId[az]), @@ -306,7 +308,7 @@ func CheckAPIServerConnectivityFromPods(azToPod map[string]coreV1.Pod, azToazId }, } - _, err = f.CloudServices.CloudWatch().PutMetricData(&putmetricData) + _, err = f.CloudServices.CloudWatch().PutMetricData(context.TODO(), &putmetricData) Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("Error while putting metric data for API Server Connectivity from %s", az)) } } @@ -327,12 +329,12 @@ func CheckConnectivityBetweenPods(azToPod map[string]coreV1.Pod, azToazId map[st if f.Options.PublishCWMetrics { putmetricData := cloudwatch.PutMetricDataInput{ Namespace: aws.String(MetricNamespace), - MetricData: []*cloudwatch.MetricDatum{ + MetricData: []cloudwatchtypes.MetricDatum{ { MetricName: aws.String(MetricName), - Unit: aws.String("Count"), + Unit: cloudwatchtypes.StandardUnitCount, Value: aws.Float64(1), - Dimensions: []*cloudwatch.Dimension{ + Dimensions: []cloudwatchtypes.Dimension{ { Name: aws.String("AZID"), Value: aws.String(azToazId[az1]), @@ -341,7 +343,7 @@ func CheckConnectivityBetweenPods(azToPod map[string]coreV1.Pod, azToazId map[st }, }, } - _, err := f.CloudServices.CloudWatch().PutMetricData(&putmetricData) + _, err := f.CloudServices.CloudWatch().PutMetricData(context.TODO(), &putmetricData) Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("Error while putting metric data for API Server Connectivity from %s", azToazId[az1])) } } @@ -367,7 +369,7 @@ func testConnectivity(senderPod coreV1.Pod, receiverPod coreV1.Pod, expectedStdo testerCommand := getTestCommandFunc(receiverPod, port) - fmt.Fprintf(GinkgoWriter, "verifying connectivity from pod %s on node %s with IP %s to pod"+ + _, _ = fmt.Fprintf(GinkgoWriter, "verifying connectivity from pod %s on node %s with IP %s to pod"+ " %s on node %s with IP %s\n", senderPod.Name, senderPod.Spec.NodeName, senderPod.Status.PodIP, receiverPod.Name, receiverPod.Spec.NodeName, receiverPod.Status.PodIP) @@ -375,7 +377,7 @@ func testConnectivity(senderPod coreV1.Pod, receiverPod coreV1.Pod, expectedStdo PodExec(senderPod.Namespace, senderPod.Name, testerCommand) Expect(err).ToNot(HaveOccurred()) - fmt.Fprintf(GinkgoWriter, "stdout: %s and stderr: %s\n", stdOut, stdErr) + _, _ = fmt.Fprintf(GinkgoWriter, "stdout: %s and stderr: %s\n", stdOut, stdErr) Expect(stdErr).To(ContainSubstring(expectedStderr)) Expect(stdOut).To(ContainSubstring(expectedStdout)) diff --git a/test/integration/cni-egress/pod_egress_suite_test.go b/test/integration/cni-egress/pod_egress_suite_test.go index 831935bb43..c9b4452434 100644 --- a/test/integration/cni-egress/pod_egress_suite_test.go +++ b/test/integration/cni-egress/pod_egress_suite_test.go @@ -14,6 +14,7 @@ package cni_egress import ( + "context" "fmt" "testing" @@ -60,14 +61,14 @@ var _ = BeforeSuite(func() { f = framework.New(framework.GlobalOptions) By("checking cluster v4 or v6") - clusterOutput, err := f.CloudServices.EKS().DescribeCluster(f.Options.ClusterName) + clusterOutput, err := f.CloudServices.EKS().DescribeCluster(context.TODO(), f.Options.ClusterName) Expect(err).NotTo(HaveOccurred()) isIPv4Cluster = false - if *clusterOutput.Cluster.KubernetesNetworkConfig.IpFamily == "ipv4" { + if clusterOutput.Cluster.KubernetesNetworkConfig.IpFamily == "ipv4" { isIPv4Cluster = true } By("creating test namespace") - f.K8sResourceManagers.NamespaceManager(). + _ = f.K8sResourceManagers.NamespaceManager(). CreateNamespace(utils.DefaultTestNamespace) By(fmt.Sprintf("getting the node with the node label key %s and value %s", @@ -90,7 +91,7 @@ var _ = BeforeSuite(func() { Expect(primaryNode.Name).To(Not(HaveLen(0)), "expected to find a non-tainted node") instanceID := k8sUtils.GetInstanceIDFromNode(primaryNode) - primaryInstance, err := f.CloudServices.EC2().DescribeInstance(instanceID) + primaryInstance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) Expect(err).ToNot(HaveOccurred()) if isIPv4Cluster { @@ -104,7 +105,7 @@ var _ = BeforeSuite(func() { instanceType := primaryNode.Labels[InstanceTypeNodeLabelKey] By("getting the network interface details from ec2") - instanceOutput, err := f.CloudServices.EC2().DescribeInstanceType(instanceType) + instanceOutput, err := f.CloudServices.EC2().DescribeInstanceType(context.TODO(), instanceType) Expect(err).ToNot(HaveOccurred()) // Subtract 2 for coredns pods if any, both could be on same Interface diff --git a/test/integration/cni-egress/pod_egress_test.go b/test/integration/cni-egress/pod_egress_test.go index c1766677f7..74d59b2514 100644 --- a/test/integration/cni-egress/pod_egress_test.go +++ b/test/integration/cni-egress/pod_egress_test.go @@ -17,7 +17,7 @@ import ( "fmt" "strings" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" v1 "k8s.io/api/apps/v1" diff --git a/test/integration/cni-upgrade-downgrade/upgrade_downgrade_suite_test.go b/test/integration/cni-upgrade-downgrade/upgrade_downgrade_suite_test.go index 0250f9740a..59fd443e4b 100644 --- a/test/integration/cni-upgrade-downgrade/upgrade_downgrade_suite_test.go +++ b/test/integration/cni-upgrade-downgrade/upgrade_downgrade_suite_test.go @@ -1,6 +1,7 @@ package cni_upgrade_downgrade import ( + "context" "fmt" "testing" @@ -54,7 +55,7 @@ var _ = BeforeSuite(func() { // Get the node security group instanceID := k8sUtils.GetInstanceIDFromNode(primaryNode) - primaryInstance, err := f.CloudServices.EC2().DescribeInstance(instanceID) + primaryInstance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) Expect(err).ToNot(HaveOccurred()) // This won't work if the first SG is only associated with the primary instance. @@ -65,14 +66,14 @@ var _ = BeforeSuite(func() { instanceType := primaryNode.Labels[InstanceTypeNodeLabelKey] By("getting the network interface details from ec2") - instanceOutput, err := f.CloudServices.EC2().DescribeInstanceType(instanceType) + instanceOutput, err := f.CloudServices.EC2().DescribeInstanceType(context.TODO(), instanceType) Expect(err).ToNot(HaveOccurred()) // Subtract 2 for coredns pods if present, and both could be on same ENI maxIPPerInterface = int(*instanceOutput[0].NetworkInfo.Ipv4AddressesPerInterface) - 2 By("describing the VPC to get the VPC CIDRs") - describeVPCOutput, err := f.CloudServices.EC2().DescribeVPC(f.Options.AWSVPCID) + describeVPCOutput, err := f.CloudServices.EC2().DescribeVPC(context.TODO(), f.Options.AWSVPCID) Expect(err).ToNot(HaveOccurred()) for _, cidrBlockAssociationSet := range describeVPCOutput.Vpcs[0].CidrBlockAssociationSet { diff --git a/test/integration/cni/pod_networking_suite_test.go b/test/integration/cni/pod_networking_suite_test.go index f2aaa69c3f..1e3da1dc09 100644 --- a/test/integration/cni/pod_networking_suite_test.go +++ b/test/integration/cni/pod_networking_suite_test.go @@ -14,6 +14,7 @@ package cni import ( + "context" "fmt" "testing" @@ -75,7 +76,7 @@ var _ = BeforeSuite(func() { // Get the node security group instanceID := k8sUtils.GetInstanceIDFromNode(primaryNode) - primaryInstance, err := f.CloudServices.EC2().DescribeInstance(instanceID) + primaryInstance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) Expect(err).ToNot(HaveOccurred()) // This won't work if the first SG is only associated with the primary instance. @@ -86,14 +87,14 @@ var _ = BeforeSuite(func() { instanceType := primaryNode.Labels[InstanceTypeNodeLabelKey] By("getting the network interface details from ec2") - instanceOutput, err := f.CloudServices.EC2().DescribeInstanceType(instanceType) + instanceOutput, err := f.CloudServices.EC2().DescribeInstanceType(context.TODO(), instanceType) Expect(err).ToNot(HaveOccurred()) // Subtract 2 for coredns pods if any, both could be on same Interface maxIPPerInterface = int(*instanceOutput[0].NetworkInfo.Ipv4AddressesPerInterface) - 2 By("describing the VPC to get the VPC CIDRs") - describeVPCOutput, err := f.CloudServices.EC2().DescribeVPC(f.Options.AWSVPCID) + describeVPCOutput, err := f.CloudServices.EC2().DescribeVPC(context.TODO(), f.Options.AWSVPCID) Expect(err).ToNot(HaveOccurred()) for _, cidrBlockAssociationSet := range describeVPCOutput.Vpcs[0].CidrBlockAssociationSet { diff --git a/test/integration/cni/pod_traffic_test.go b/test/integration/cni/pod_traffic_test.go index f63ba4a430..bcd5794009 100644 --- a/test/integration/cni/pod_traffic_test.go +++ b/test/integration/cni/pod_traffic_test.go @@ -14,6 +14,7 @@ package cni import ( + "context" "fmt" "strconv" @@ -22,7 +23,6 @@ import ( "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/manifest" - "github.com/aws/aws-sdk-go/service/ec2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" v1 "k8s.io/api/apps/v1" @@ -72,12 +72,12 @@ var _ = Describe("test pod networking", func() { JustBeforeEach(func() { By("authorizing security group ingress on instance security group") err = f.CloudServices.EC2(). - AuthorizeSecurityGroupIngress(instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0", false) + AuthorizeSecurityGroupIngress(context.TODO(), instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0", false) Expect(err).ToNot(HaveOccurred()) By("authorizing security group egress on instance security group") err = f.CloudServices.EC2(). - AuthorizeSecurityGroupEgress(instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0") + AuthorizeSecurityGroupEgress(context.TODO(), instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0") Expect(err).ToNot(HaveOccurred()) serverContainer := manifest. @@ -139,12 +139,12 @@ var _ = Describe("test pod networking", func() { JustAfterEach(func() { By("revoking security group ingress on instance security group") err = f.CloudServices.EC2(). - RevokeSecurityGroupIngress(instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0", false) + RevokeSecurityGroupIngress(context.TODO(), instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0", false) Expect(err).ToNot(HaveOccurred()) By("revoking security group egress on instance security group") err = f.CloudServices.EC2(). - RevokeSecurityGroupEgress(instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0") + RevokeSecurityGroupEgress(context.TODO(), instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0") Expect(err).ToNot(HaveOccurred()) By("deleting the primary node server deployment") @@ -190,7 +190,7 @@ var _ = Describe("test pod networking", func() { Context("[CANARY][SMOKE] when establishing UDP connection from tester to server", func() { BeforeEach(func() { serverPort = 2273 - protocol = ec2.ProtocolUdp + protocol = "udp" serverListenCmd = []string{"nc"} // The nc flag "-l" for listen mode, "-k" to keep server up and not close // connection after each connection, "-u" for udp @@ -229,7 +229,7 @@ var _ = Describe("test pod networking", func() { BeforeEach(func() { serverPort = 2273 - protocol = ec2.ProtocolTcp + protocol = "tcp" // Test tcp connection using netcat serverListenCmd = []string{"nc"} // The nc flag "-l" for listen mode, "-k" to keep server up and not close @@ -270,7 +270,7 @@ func VerifyConnectivityFailsForNegativeCase(senderPod coreV1.Pod, receiverPod co testerCommand := getTestCommandFunc(receiverPod, port) - fmt.Fprintf(GinkgoWriter, "verifying connectivity fails from pod %s on node %s with IP %s to pod"+ + _, _ = fmt.Fprintf(GinkgoWriter, "verifying connectivity fails from pod %s on node %s with IP %s to pod"+ " %s on node %s with IP %s\n", senderPod.Name, senderPod.Spec.NodeName, senderPod.Status.PodIP, receiverPod.Name, receiverPod.Spec.NodeName, receiverPod.Status.PodIP) @@ -330,7 +330,7 @@ func testConnectivity(senderPod coreV1.Pod, receiverPod coreV1.Pod, expectedStdo testerCommand := getTestCommandFunc(receiverPod, port) - fmt.Fprintf(GinkgoWriter, "verifying connectivity from pod %s on node %s with IP %s to pod"+ + _, _ = fmt.Fprintf(GinkgoWriter, "verifying connectivity from pod %s on node %s with IP %s to pod"+ " %s on node %s with IP %s\n", senderPod.Name, senderPod.Spec.NodeName, senderPod.Status.PodIP, receiverPod.Name, receiverPod.Spec.NodeName, receiverPod.Status.PodIP) @@ -338,7 +338,7 @@ func testConnectivity(senderPod coreV1.Pod, receiverPod coreV1.Pod, expectedStdo PodExec(senderPod.Namespace, senderPod.Name, testerCommand) Expect(err).ToNot(HaveOccurred()) - fmt.Fprintf(GinkgoWriter, "stdout: %s and stderr: %s\n", stdOut, stdErr) + _, _ = fmt.Fprintf(GinkgoWriter, "stdout: %s and stderr: %s\n", stdOut, stdErr) Expect(stdErr).To(ContainSubstring(expectedStderr)) Expect(stdOut).To(ContainSubstring(expectedStdout)) diff --git a/test/integration/cni/service_connectivity_test.go b/test/integration/cni/service_connectivity_test.go index f085baa101..c38f9175d9 100644 --- a/test/integration/cni/service_connectivity_test.go +++ b/test/integration/cni/service_connectivity_test.go @@ -139,7 +139,7 @@ var _ = Describe("[CANARY] test service connectivity", FlakeAttempts(3), func() // since pod placement is not guaranteed to be equally distributed By("checking number of ENIs is less than or equal to maxENIs") instanceID := k8sUtils.GetInstanceIDFromNode(primaryNode) - primaryInstance, err := f.CloudServices.EC2().DescribeInstance(instanceID) + primaryInstance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) Expect(err).ToNot(HaveOccurred()) Expect(len(primaryInstance.NetworkInterfaces) <= 3).To(BeTrue()) }) diff --git a/test/integration/cni/soak_test.go b/test/integration/cni/soak_test.go index 8819a8b5ce..959a5a6ff0 100644 --- a/test/integration/cni/soak_test.go +++ b/test/integration/cni/soak_test.go @@ -14,15 +14,14 @@ package cni import ( + "context" "fmt" "strconv" "time" + "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/manifest" "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" "github.com/aws/amazon-vpc-cni-k8s/test/integration/common" - "github.com/aws/aws-sdk-go/service/ec2" - - "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/manifest" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -59,17 +58,17 @@ var _ = Describe("SOAK Test pod networking", Ordered, func() { BeforeAll(func() { fmt.Println("Starting SOAK test") - protocol = ec2.ProtocolTcp + protocol = "tcp" serverPort = 2273 By("Authorize Security Group Ingress on EC2 instance.") err = f.CloudServices.EC2(). - AuthorizeSecurityGroupIngress(instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0", false) + AuthorizeSecurityGroupIngress(context.TODO(), instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0", false) Expect(err).ToNot(HaveOccurred()) By("Authorize Security Group Egress on EC2 instance.") err = f.CloudServices.EC2(). - AuthorizeSecurityGroupEgress(instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0") + AuthorizeSecurityGroupEgress(context.TODO(), instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0") Expect(err).ToNot(HaveOccurred()) }) @@ -78,12 +77,12 @@ var _ = Describe("SOAK Test pod networking", Ordered, func() { By("Revoke Security Group Ingress.") err = f.CloudServices.EC2(). - RevokeSecurityGroupIngress(instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0", false) + RevokeSecurityGroupIngress(context.TODO(), instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0", false) Expect(err).ToNot(HaveOccurred()) By("Revoke Security Group Egress.") err = f.CloudServices.EC2(). - RevokeSecurityGroupEgress(instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0") + RevokeSecurityGroupEgress(context.TODO(), instanceSecurityGroupID, protocol, serverPort, serverPort, "0.0.0.0/0") Expect(err).ToNot(HaveOccurred()) By("SOAK test completed") diff --git a/test/integration/common/util.go b/test/integration/common/util.go index a451a77aff..a986b5cf8d 100644 --- a/test/integration/common/util.go +++ b/test/integration/common/util.go @@ -2,13 +2,15 @@ package common import ( "bytes" + "context" "fmt" "io" "os" "os/exec" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/aws/amazon-vpc-cni-k8s/test/agent/pkg/input" - "github.com/aws/aws-sdk-go/service/ec2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" coreV1 "k8s.io/api/core/v1" @@ -105,7 +107,7 @@ func ValidateHostNetworking(testType TestType, podValidationInputString string, PodLogs(testPod.Namespace, testPod.Name) Expect(errLogs).ToNot(HaveOccurred()) - fmt.Fprintln(GinkgoWriter, logs) + _, _ = fmt.Fprintln(GinkgoWriter, logs) if shouldTestPodError { Expect(err).To(HaveOccurred()) @@ -128,7 +130,7 @@ func GetPodsOnPrimaryAndSecondaryInterface(node coreV1.Node, Expect(err).ToNot(HaveOccurred()) instance, err := f.CloudServices.EC2(). - DescribeInstance(k8sUtils.GetInstanceIDFromNode(node)) + DescribeInstance(context.TODO(), k8sUtils.GetInstanceIDFromNode(node)) Expect(err).ToNot(HaveOccurred()) interfaceToPodList := InterfaceTypeToPodList{ @@ -173,7 +175,7 @@ func GetTrafficTestConfig(f *framework.Framework, protocol string, serverDeploym } } -func IsPrimaryENI(nwInterface *ec2.InstanceNetworkInterface, instanceIPAddr *string) bool { +func IsPrimaryENI(nwInterface ec2types.InstanceNetworkInterface, instanceIPAddr *string) bool { for _, privateIPAddress := range nwInterface.PrivateIpAddresses { if *privateIPAddress.PrivateIpAddress == *instanceIPAddr { return true diff --git a/test/integration/custom-networking-sgpp/custom_networking_sgpp_suite_test.go b/test/integration/custom-networking-sgpp/custom_networking_sgpp_suite_test.go index 085309d2af..36c6a29ac3 100644 --- a/test/integration/custom-networking-sgpp/custom_networking_sgpp_suite_test.go +++ b/test/integration/custom-networking-sgpp/custom_networking_sgpp_suite_test.go @@ -14,6 +14,7 @@ package custom_networking_sgpp import ( + "context" "flag" "fmt" "net" @@ -85,25 +86,25 @@ var _ = BeforeSuite(func() { Expect(err).ToNot(HaveOccurred()) By("Getting Cluster Security Group ID") - clusterRes, err := f.CloudServices.EKS().DescribeCluster(f.Options.ClusterName) + clusterRes, err := f.CloudServices.EKS().DescribeCluster(context.TODO(), f.Options.ClusterName) Expect(err).NotTo(HaveOccurred()) clusterSGID = *(clusterRes.Cluster.ResourcesVpcConfig.ClusterSecurityGroupId) - fmt.Fprintf(GinkgoWriter, "cluster security group is %s\n", clusterSGID) + _, _ = fmt.Fprintf(GinkgoWriter, "cluster security group is %s\n", clusterSGID) // Custom Networking setup // TODO: Ideally, we would clone the Custom Networking SG from the cluster SG. Unfortunately, the EC2 API does not support this. By("creating security group to be used by custom networking") createSecurityGroupOutput, err := f.CloudServices.EC2(). - CreateSecurityGroup("custom-networking-test", "custom networking", f.Options.AWSVPCID) + CreateSecurityGroup(context.TODO(), "custom-networking-test", "custom networking", f.Options.AWSVPCID) Expect(err).ToNot(HaveOccurred()) customNetworkingSGID = *createSecurityGroupOutput.GroupId By("authorizing egress and ingress for security group in ENIConfig") - f.CloudServices.EC2().AuthorizeSecurityGroupEgress(customNetworkingSGID, "-1", -1, -1, v4Zero) - f.CloudServices.EC2().AuthorizeSecurityGroupIngress(customNetworkingSGID, "-1", -1, -1, v4Zero, false) + _ = f.CloudServices.EC2().AuthorizeSecurityGroupEgress(context.TODO(), customNetworkingSGID, "-1", -1, -1, v4Zero) + _ = f.CloudServices.EC2().AuthorizeSecurityGroupIngress(context.TODO(), customNetworkingSGID, "-1", -1, -1, v4Zero, false) By("associating cidr range to the VPC") - association, err := f.CloudServices.EC2().AssociateVPCCIDRBlock(f.Options.AWSVPCID, cidrRange.String()) + association, err := f.CloudServices.EC2().AssociateVPCCIDRBlock(context.TODO(), f.Options.AWSVPCID, cidrRange.String()) Expect(err).ToNot(HaveOccurred()) cidrBlockAssociationID = *association.CidrBlockAssociation.AssociationId @@ -114,13 +115,13 @@ var _ = BeforeSuite(func() { Expect(err).ToNot(HaveOccurred()) createSubnetOutput, err := f.CloudServices.EC2(). - CreateSubnet(subnetCidr.String(), f.Options.AWSVPCID, az) + CreateSubnet(context.TODO(), subnetCidr.String(), f.Options.AWSVPCID, az) Expect(err).ToNot(HaveOccurred()) subnetID := *createSubnetOutput.Subnet.SubnetId By("associating the route table with the newly created subnet") - err = f.CloudServices.EC2().AssociateRouteTableToSubnet(clusterVPCConfig.PublicRouteTableID, subnetID) + err = f.CloudServices.EC2().AssociateRouteTableToSubnet(context.TODO(), clusterVPCConfig.PublicRouteTableID, subnetID) Expect(err).ToNot(HaveOccurred()) eniConfigBuilder := manifest.NewENIConfigBuilder(). @@ -144,14 +145,14 @@ var _ = BeforeSuite(func() { // Note that Custom Networking only supports IPv4 clusters, so IPv4 setup can be assumed. By("creating a new security group for use in Security Group Policy") podEniSGName := "pod-eni-automation-v4" - securityGroupOutput, err := f.CloudServices.EC2().CreateSecurityGroup(podEniSGName, + securityGroupOutput, err := f.CloudServices.EC2().CreateSecurityGroup(context.TODO(), podEniSGName, "test created by vpc cni automation test suite", f.Options.AWSVPCID) Expect(err).ToNot(HaveOccurred()) podEniSGID = *securityGroupOutput.GroupId By("authorizing egress and ingress on security group for client-server communication") - f.CloudServices.EC2().AuthorizeSecurityGroupEgress(podEniSGID, "tcp", podEniOpenPort, podEniOpenPort, v4Zero) - f.CloudServices.EC2().AuthorizeSecurityGroupIngress(podEniSGID, "tcp", podEniOpenPort, podEniOpenPort, v4Zero, false) + _ = f.CloudServices.EC2().AuthorizeSecurityGroupEgress(context.TODO(), podEniSGID, "tcp", podEniOpenPort, podEniOpenPort, v4Zero) + _ = f.CloudServices.EC2().AuthorizeSecurityGroupIngress(context.TODO(), podEniSGID, "tcp", podEniOpenPort, podEniOpenPort, v4Zero, false) By("getting branch ENI limits") nodeList, err := f.K8sResourceManagers.NodeManager().GetNodes(f.Options.NgNameLabelKey, f.Options.NgNameLabelVal) @@ -161,9 +162,9 @@ var _ = BeforeSuite(func() { node := nodeList.Items[0] instanceID := k8sUtils.GetInstanceIDFromNode(node) - nodeInstance, err := f.CloudServices.EC2().DescribeInstance(instanceID) - instanceType := *nodeInstance.InstanceType - totalBranchInterface = vpc.Limits[instanceType].BranchInterface * numNodes + nodeInstance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) + instanceType := nodeInstance.InstanceType + totalBranchInterface = vpc.Limits[string(instanceType)].BranchInterface * numNodes By("enabling custom networking and sgpp on aws-node DaemonSet") k8sUtils.AddEnvVarToDaemonSetAndWaitTillUpdated(f, utils.AwsNodeName, @@ -202,18 +203,18 @@ var _ = AfterSuite(func() { errs.Append(awsUtils.TerminateInstances(f)) By("deleting Custom Networking security group") - errs.Append(f.CloudServices.EC2().DeleteSecurityGroup(customNetworkingSGID)) + errs.Append(f.CloudServices.EC2().DeleteSecurityGroup(context.TODO(), customNetworkingSGID)) By("deleting pod ENI security group") - errs.Append(f.CloudServices.EC2().DeleteSecurityGroup(podEniSGID)) + errs.Append(f.CloudServices.EC2().DeleteSecurityGroup(context.TODO(), podEniSGID)) for _, subnet := range customNetworkingSubnetIDList { By(fmt.Sprintf("deleting the subnet %s", subnet)) - errs.Append(f.CloudServices.EC2().DeleteSubnet(subnet)) + errs.Append(f.CloudServices.EC2().DeleteSubnet(context.TODO(), subnet)) } By("disassociating the CIDR range to the VPC") - errs.Append(f.CloudServices.EC2().DisAssociateVPCCIDRBlock(cidrBlockAssociationID)) + errs.Append(f.CloudServices.EC2().DisAssociateVPCCIDRBlock(context.TODO(), cidrBlockAssociationID)) Expect(errs.MaybeUnwrap()).ToNot(HaveOccurred()) }) diff --git a/test/integration/custom-networking-sgpp/trunk_test.go b/test/integration/custom-networking-sgpp/trunk_test.go index f96d972c10..481d2eb4f7 100644 --- a/test/integration/custom-networking-sgpp/trunk_test.go +++ b/test/integration/custom-networking-sgpp/trunk_test.go @@ -14,6 +14,8 @@ package custom_networking_sgpp import ( + "context" + k8sUtils "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/utils" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -23,7 +25,7 @@ var _ = Describe("Trunk ENI Security Group Test", func() { Context("when validating security group on trunk ENI", func() { It("should match security group in ENIConfig", func() { instanceID := k8sUtils.GetInstanceIDFromNode(targetNode) - instance, err := f.CloudServices.EC2().DescribeInstance(instanceID) + instance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) Expect(err).ToNot(HaveOccurred()) trunkSGMatch := false diff --git a/test/integration/custom-networking/custom_networking_suite_test.go b/test/integration/custom-networking/custom_networking_suite_test.go index 0dd8ac9301..1b16257b25 100644 --- a/test/integration/custom-networking/custom_networking_suite_test.go +++ b/test/integration/custom-networking/custom_networking_suite_test.go @@ -14,6 +14,7 @@ package custom_networking import ( + "context" "flag" "fmt" "net" @@ -82,22 +83,22 @@ var _ = BeforeSuite(func() { By("creating security group to be used by custom networking") createSecurityGroupOutput, err := f.CloudServices.EC2(). - CreateSecurityGroup("custom-networking-test", "custom networking", f.Options.AWSVPCID) + CreateSecurityGroup(context.TODO(), "custom-networking-test", "custom networking", f.Options.AWSVPCID) Expect(err).ToNot(HaveOccurred()) customNetworkingSGID = *createSecurityGroupOutput.GroupId By("authorizing egress and ingress on security group for single port") - f.CloudServices.EC2().AuthorizeSecurityGroupEgress(customNetworkingSGID, "TCP", + f.CloudServices.EC2().AuthorizeSecurityGroupEgress(context.TODO(), customNetworkingSGID, "TCP", customNetworkingSGOpenPort, customNetworkingSGOpenPort, "0.0.0.0/0") - f.CloudServices.EC2().AuthorizeSecurityGroupIngress(customNetworkingSGID, "TCP", + f.CloudServices.EC2().AuthorizeSecurityGroupIngress(context.TODO(), customNetworkingSGID, "TCP", customNetworkingSGOpenPort, customNetworkingSGOpenPort, "0.0.0.0/0", false) - f.CloudServices.EC2().AuthorizeSecurityGroupEgress(customNetworkingSGID, "UDP", + f.CloudServices.EC2().AuthorizeSecurityGroupEgress(context.TODO(), customNetworkingSGID, "UDP", corednsSGOpenPort, corednsSGOpenPort, "0.0.0.0/0") - f.CloudServices.EC2().AuthorizeSecurityGroupIngress(customNetworkingSGID, "UDP", + f.CloudServices.EC2().AuthorizeSecurityGroupIngress(context.TODO(), customNetworkingSGID, "UDP", corednsSGOpenPort, corednsSGOpenPort, "0.0.0.0/0", false) - f.CloudServices.EC2().AuthorizeSecurityGroupEgress(customNetworkingSGID, "TCP", + f.CloudServices.EC2().AuthorizeSecurityGroupEgress(context.TODO(), customNetworkingSGID, "TCP", corednsSGOpenPort, corednsSGOpenPort, "0.0.0.0/0") - f.CloudServices.EC2().AuthorizeSecurityGroupIngress(customNetworkingSGID, "TCP", + f.CloudServices.EC2().AuthorizeSecurityGroupIngress(context.TODO(), customNetworkingSGID, "TCP", corednsSGOpenPort, corednsSGOpenPort, "0.0.0.0/0", false) By("Adding custom networking security group ingress rule from primary eni") @@ -115,10 +116,10 @@ var _ = BeforeSuite(func() { Expect(primaryNode).To(Not(BeNil()), "expected to find a non-tainted node") instanceID := k8sUtils.GetInstanceIDFromNode(*primaryNode) - primaryInstance, err := f.CloudServices.EC2().DescribeInstance(instanceID) + primaryInstance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) Expect(err).ToNot(HaveOccurred()) - instance, err := f.CloudServices.EC2().DescribeInstance(*primaryInstance.InstanceId) + instance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), *primaryInstance.InstanceId) Expect(err).ToNot(HaveOccurred()) var primaryENIID string @@ -130,16 +131,16 @@ var _ = BeforeSuite(func() { } } - eniOutput, err := f.CloudServices.EC2().DescribeNetworkInterface([]string{primaryENIID}) + eniOutput, err := f.CloudServices.EC2().DescribeNetworkInterface(context.TODO(), []string{primaryENIID}) Expect(err).ToNot(HaveOccurred()) for _, sg := range eniOutput.NetworkInterfaces[0].Groups { primaryENISGList = append(primaryENISGList, *sg.GroupId) - f.CloudServices.EC2().AuthorizeSecurityGroupIngress(*sg.GroupId, "-1", + f.CloudServices.EC2().AuthorizeSecurityGroupIngress(context.TODO(), *sg.GroupId, "-1", -1, -1, customNetworkingSGID, true) } By("associating cidr range to the VPC") - association, err := f.CloudServices.EC2().AssociateVPCCIDRBlock(f.Options.AWSVPCID, cidrRange.String()) + association, err := f.CloudServices.EC2().AssociateVPCCIDRBlock(context.TODO(), f.Options.AWSVPCID, cidrRange.String()) Expect(err).ToNot(HaveOccurred()) cidrBlockAssociationID = *association.CidrBlockAssociation.AssociationId @@ -150,13 +151,13 @@ var _ = BeforeSuite(func() { Expect(err).ToNot(HaveOccurred()) createSubnetOutput, err := f.CloudServices.EC2(). - CreateSubnet(subnetCidr.String(), f.Options.AWSVPCID, az) + CreateSubnet(context.TODO(), subnetCidr.String(), f.Options.AWSVPCID, az) Expect(err).ToNot(HaveOccurred()) subnetID := *createSubnetOutput.Subnet.SubnetId By("associating the route table with the newly created subnet") - err = f.CloudServices.EC2().AssociateRouteTableToSubnet(clusterVPCConfig.PublicRouteTableID, subnetID) + err = f.CloudServices.EC2().AssociateRouteTableToSubnet(context.TODO(), clusterVPCConfig.PublicRouteTableID, subnetID) Expect(err).ToNot(HaveOccurred()) eniConfigBuilder := manifest.NewENIConfigBuilder(). @@ -213,20 +214,20 @@ var _ = AfterSuite(func() { By("Removing custom networking security group ingress rule from primary eni") for _, sg := range primaryENISGList { - f.CloudServices.EC2().RevokeSecurityGroupIngress(sg, "-1", + _ = f.CloudServices.EC2().RevokeSecurityGroupIngress(context.TODO(), sg, "-1", -1, -1, customNetworkingSGID, true) } By("deleting security group") - errs.Append(f.CloudServices.EC2().DeleteSecurityGroup(customNetworkingSGID)) + errs.Append(f.CloudServices.EC2().DeleteSecurityGroup(context.TODO(), customNetworkingSGID)) for _, subnet := range customNetworkingSubnetIDList { By(fmt.Sprintf("deleting the subnet %s", subnet)) - errs.Append(f.CloudServices.EC2().DeleteSubnet(subnet)) + errs.Append(f.CloudServices.EC2().DeleteSubnet(context.TODO(), subnet)) } By("disassociating the CIDR range to the VPC") - errs.Append(f.CloudServices.EC2().DisAssociateVPCCIDRBlock(cidrBlockAssociationID)) + errs.Append(f.CloudServices.EC2().DisAssociateVPCCIDRBlock(context.TODO(), cidrBlockAssociationID)) Expect(errs.MaybeUnwrap()).ToNot(HaveOccurred()) }) diff --git a/test/integration/eni-subnet-discovery/eni_subnet_discovery_suite_test.go b/test/integration/eni-subnet-discovery/eni_subnet_discovery_suite_test.go index ed83c71ead..e5509ee814 100644 --- a/test/integration/eni-subnet-discovery/eni_subnet_discovery_suite_test.go +++ b/test/integration/eni-subnet-discovery/eni_subnet_discovery_suite_test.go @@ -14,18 +14,20 @@ package eni_subnet_discovery import ( + "context" "flag" "fmt" "net" "testing" "time" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/apparentlymart/go-cidr/cidr" "github.com/aws/amazon-vpc-cni-k8s/test/framework" awsUtils "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/aws/utils" k8sUtils "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/utils" "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" - "github.com/aws/aws-sdk-go/service/ec2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/prometheus/client_golang/prometheus" @@ -44,7 +46,7 @@ var ( cidrRange *net.IPNet cidrBlockAssociationID string createdSubnet string - primaryInstance *ec2.Instance + primaryInstance ec2types.Instance ) // Parse test specific variable from flag @@ -74,21 +76,21 @@ var _ = BeforeSuite(func() { Expect(primaryNode).To(Not(BeNil()), "expected to find a non-tainted node") instanceID := k8sUtils.GetInstanceIDFromNode(*primaryNode) - primaryInstance, err = f.CloudServices.EC2().DescribeInstance(instanceID) + primaryInstance, err = f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) Expect(err).ToNot(HaveOccurred()) _, cidrRange, err = net.ParseCIDR(cidrRangeString) Expect(err).ToNot(HaveOccurred()) By("creating test namespace") - f.K8sResourceManagers.NamespaceManager().CreateNamespace(utils.DefaultTestNamespace) + _ = f.K8sResourceManagers.NamespaceManager().CreateNamespace(utils.DefaultTestNamespace) By("getting the cluster VPC Config") clusterVPCConfig, err = awsUtils.GetClusterVPCConfig(f) Expect(err).ToNot(HaveOccurred()) By("associating cidr range to the VPC") - association, err := f.CloudServices.EC2().AssociateVPCCIDRBlock(f.Options.AWSVPCID, cidrRange.String()) + association, err := f.CloudServices.EC2().AssociateVPCCIDRBlock(context.TODO(), f.Options.AWSVPCID, cidrRange.String()) Expect(err).ToNot(HaveOccurred()) cidrBlockAssociationID = *association.CidrBlockAssociation.AssociationId @@ -99,13 +101,13 @@ var _ = BeforeSuite(func() { Expect(err).ToNot(HaveOccurred()) createSubnetOutput, err := f.CloudServices.EC2(). - CreateSubnet(subnetCidr.String(), f.Options.AWSVPCID, *primaryInstance.Placement.AvailabilityZone) + CreateSubnet(context.TODO(), subnetCidr.String(), f.Options.AWSVPCID, *primaryInstance.Placement.AvailabilityZone) Expect(err).ToNot(HaveOccurred()) subnetID := *createSubnetOutput.Subnet.SubnetId By("associating the route table with the newly created subnet") - err = f.CloudServices.EC2().AssociateRouteTableToSubnet(clusterVPCConfig.PublicRouteTableID, subnetID) + err = f.CloudServices.EC2().AssociateRouteTableToSubnet(context.TODO(), clusterVPCConfig.PublicRouteTableID, subnetID) Expect(err).ToNot(HaveOccurred()) By("try detaching all ENIs by setting WARM_ENI_TARGET to 0") @@ -120,7 +122,7 @@ var _ = BeforeSuite(func() { var _ = AfterSuite(func() { By("deleting test namespace") - f.K8sResourceManagers.NamespaceManager(). + _ = f.K8sResourceManagers.NamespaceManager(). DeleteAndWaitTillNamespaceDeleted(utils.DefaultTestNamespace) var errs prometheus.MultiError @@ -129,10 +131,10 @@ var _ = AfterSuite(func() { time.Sleep(time.Second * 90) By(fmt.Sprintf("deleting the subnet %s", createdSubnet)) - errs.Append(f.CloudServices.EC2().DeleteSubnet(createdSubnet)) + errs.Append(f.CloudServices.EC2().DeleteSubnet(context.TODO(), createdSubnet)) By("disassociating the CIDR range to the VPC") - errs.Append(f.CloudServices.EC2().DisAssociateVPCCIDRBlock(cidrBlockAssociationID)) + errs.Append(f.CloudServices.EC2().DisAssociateVPCCIDRBlock(context.TODO(), cidrBlockAssociationID)) Expect(errs.MaybeUnwrap()).ToNot(HaveOccurred()) diff --git a/test/integration/eni-subnet-discovery/eni_subnet_discovery_test.go b/test/integration/eni-subnet-discovery/eni_subnet_discovery_test.go index c2fe33c6ad..105d959d63 100644 --- a/test/integration/eni-subnet-discovery/eni_subnet_discovery_test.go +++ b/test/integration/eni-subnet-discovery/eni_subnet_discovery_test.go @@ -14,6 +14,7 @@ package eni_subnet_discovery import ( + "context" "fmt" "net" "os" @@ -21,12 +22,13 @@ import ( "strings" "time" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/manifest" k8sUtils "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/utils" "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" "github.com/aws/amazon-vpc-cni-k8s/test/integration/common" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/aws" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" v1 "k8s.io/api/apps/v1" @@ -97,8 +99,9 @@ var _ = Describe("ENI Subnet Selection Test", func() { By("Tagging kubernetes.io/role/cni to subnet") _, err = f.CloudServices.EC2(). CreateTags( + context.TODO(), []string{createdSubnet}, - []*ec2.Tag{ + []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cni"), Value: aws.String("1"), @@ -111,8 +114,9 @@ var _ = Describe("ENI Subnet Selection Test", func() { By("Untagging kubernetes.io/role/cni from subnet") _, err = f.CloudServices.EC2(). DeleteTags( + context.TODO(), []string{createdSubnet}, - []*ec2.Tag{ + []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cni"), Value: aws.String("1"), @@ -140,11 +144,11 @@ var _ = Describe("ENI Subnet Selection Test", func() { if role == "" { // get the node instance role By("getting the node instance role") instanceProfileRoleName := strings.Split(*primaryInstance.IamInstanceProfile.Arn, "instance-profile/")[1] - instanceProfileOutput, err := f.CloudServices.IAM().GetInstanceProfile(instanceProfileRoleName) + instanceProfileOutput, err := f.CloudServices.IAM().GetInstanceProfile(context.TODO(), instanceProfileRoleName) Expect(err).ToNot(HaveOccurred()) role = *instanceProfileOutput.InstanceProfile.Roles[0].RoleName } - err = f.CloudServices.IAM().DetachRolePolicy(EKSCNIPolicyARN, role) + err = f.CloudServices.IAM().DetachRolePolicy(context.TODO(), EKSCNIPolicyARN, role) Expect(err).ToNot(HaveOccurred()) eksCNIPolicyV4Path := utils.GetProjectRoot() + EKSCNIPolicyV4 @@ -154,10 +158,10 @@ var _ = Describe("ENI Subnet Selection Test", func() { eksCNIPolicyV4Data := string(eksCNIPolicyV4Bytes) By("Creating and attaching policy AmazonEKS_CNI_Policy_V4") - output, err := f.CloudServices.IAM().CreatePolicy("AmazonEKS_CNI_Policy_V4", eksCNIPolicyV4Data) + output, err := f.CloudServices.IAM().CreatePolicy(context.TODO(), "AmazonEKS_CNI_Policy_V4", eksCNIPolicyV4Data) Expect(err).ToNot(HaveOccurred()) EKSCNIPolicyV4ARN = *output.Policy.Arn - err = f.CloudServices.IAM().AttachRolePolicy(EKSCNIPolicyV4ARN, role) + err = f.CloudServices.IAM().AttachRolePolicy(context.TODO(), EKSCNIPolicyV4ARN, role) Expect(err).ToNot(HaveOccurred()) // Sleep to allow time for CNI policy reattachment @@ -168,14 +172,14 @@ var _ = Describe("ENI Subnet Selection Test", func() { AfterEach(func() { By("attaching VPC_CNI policy") - err = f.CloudServices.IAM().AttachRolePolicy(EKSCNIPolicyARN, role) + err = f.CloudServices.IAM().AttachRolePolicy(context.TODO(), EKSCNIPolicyARN, role) Expect(err).ToNot(HaveOccurred()) By("Detaching and deleting policy AmazonEKS_CNI_Policy_V4") - err = f.CloudServices.IAM().DetachRolePolicy(EKSCNIPolicyV4ARN, role) + err = f.CloudServices.IAM().DetachRolePolicy(context.TODO(), EKSCNIPolicyV4ARN, role) Expect(err).ToNot(HaveOccurred()) - err = f.CloudServices.IAM().DeletePolicy(EKSCNIPolicyV4ARN) + err = f.CloudServices.IAM().DeletePolicy(context.TODO(), EKSCNIPolicyV4ARN) Expect(err).ToNot(HaveOccurred()) // Sleep to allow time for CNI policy detachment @@ -193,8 +197,9 @@ var _ = Describe("ENI Subnet Selection Test", func() { By("Tagging kubernetes.io/role/cn to subnet") _, err = f.CloudServices.EC2(). CreateTags( + context.TODO(), []string{createdSubnet}, - []*ec2.Tag{ + []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cn"), Value: aws.String("1"), @@ -207,8 +212,9 @@ var _ = Describe("ENI Subnet Selection Test", func() { By("Untagging kubernetes.io/role/cn from subnet") _, err = f.CloudServices.EC2(). DeleteTags( + context.TODO(), []string{createdSubnet}, - []*ec2.Tag{ + []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cn"), Value: aws.String("1"), @@ -247,8 +253,9 @@ var _ = Describe("ENI Subnet Selection Test", func() { By("Tagging kubernetes.io/role/cni to subnet") _, err = f.CloudServices.EC2(). CreateTags( + context.TODO(), []string{createdSubnet}, - []*ec2.Tag{ + []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cni"), Value: aws.String("1"), @@ -261,8 +268,9 @@ var _ = Describe("ENI Subnet Selection Test", func() { By("Untagging kubernetes.io/role/cni from subnet") _, err = f.CloudServices.EC2(). DeleteTags( + context.TODO(), []string{createdSubnet}, - []*ec2.Tag{ + []ec2types.Tag{ { Key: aws.String("kubernetes.io/role/cni"), Value: aws.String("1"), @@ -280,7 +288,7 @@ var _ = Describe("ENI Subnet Selection Test", func() { }) func checkSecondaryENISubnets(expectNewCidr bool) { - instance, err := f.CloudServices.EC2().DescribeInstance(*primaryInstance.InstanceId) + instance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), *primaryInstance.InstanceId) Expect(err).ToNot(HaveOccurred()) By("retrieving secondary ENIs") @@ -294,7 +302,7 @@ func checkSecondaryENISubnets(expectNewCidr bool) { By("verifying at least one new Secondary ENI is created") Expect(len(newEniSubnetIds)).Should(BeNumerically(">", 0)) - vpcOutput, err := f.CloudServices.EC2().DescribeVPC(*primaryInstance.VpcId) + vpcOutput, err := f.CloudServices.EC2().DescribeVPC(context.TODO(), *primaryInstance.VpcId) Expect(err).ToNot(HaveOccurred()) expectedCidrRangeString := *vpcOutput.Vpcs[0].CidrBlock @@ -311,7 +319,7 @@ func checkSecondaryENISubnets(expectNewCidr bool) { By(fmt.Sprintf("checking the secondary ENI subnets are in the CIDR %s", expectedCidrRangeString)) for _, subnetID := range newEniSubnetIds { - subnetOutput, err := f.CloudServices.EC2().DescribeSubnet(subnetID) + subnetOutput, err := f.CloudServices.EC2().DescribeSubnet(context.TODO(), subnetID) Expect(err).ToNot(HaveOccurred()) cidrSplit := strings.Split(*subnetOutput.Subnets[0].CidrBlock, "/") actualSubnetIp, _, _ := net.ParseCIDR(*subnetOutput.Subnets[0].CidrBlock) @@ -326,6 +334,6 @@ func RestartAwsNodePods() { podList, err := f.K8sResourceManagers.PodManager().GetPodsWithLabelSelector(AwsNodeLabelKey, utils.AwsNodeName) Expect(err).ToNot(HaveOccurred()) for _, pod := range podList.Items { - f.K8sResourceManagers.PodManager().DeleteAndWaitTillPodDeleted(&pod) + _ = f.K8sResourceManagers.PodManager().DeleteAndWaitTillPodDeleted(&pod) } } diff --git a/test/integration/ipamd/common.go b/test/integration/ipamd/common.go index 589d6430ca..861bfc4174 100644 --- a/test/integration/ipamd/common.go +++ b/test/integration/ipamd/common.go @@ -2,10 +2,10 @@ package ipamd import ( "github.com/aws/amazon-vpc-cni-k8s/test/framework" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" ) -var primaryInstance *ec2.Instance +var primaryInstance types.Instance var f *framework.Framework var err error diff --git a/test/integration/ipamd/eni_ip_leak_test.go b/test/integration/ipamd/eni_ip_leak_test.go index 0e765c6425..cc53b179fa 100644 --- a/test/integration/ipamd/eni_ip_leak_test.go +++ b/test/integration/ipamd/eni_ip_leak_test.go @@ -1,6 +1,7 @@ package ipamd import ( + "context" "time" v1 "k8s.io/api/core/v1" @@ -74,9 +75,9 @@ func getCountOfIPandENIOnPrimaryInstance() (int, int) { return ip, eni } -func getMaxApplicationPodsOnPrimaryInstance() int64 { +func getMaxApplicationPodsOnPrimaryInstance() int32 { instanceType := primaryInstance.InstanceType - instanceInfo, err := f.CloudServices.EC2().DescribeInstanceType(*instanceType) + instanceInfo, err := f.CloudServices.EC2().DescribeInstanceType(context.TODO(), string(instanceType)) Expect(err).NotTo(HaveOccurred()) currInstance := instanceInfo[0] @@ -84,6 +85,6 @@ func getMaxApplicationPodsOnPrimaryInstance() int64 { maxIPPerENI := currInstance.NetworkInfo.Ipv4AddressesPerInterface // Deploy 50% of max pod capacity - maxPods := *maxENI*(*maxIPPerENI-1) - int64(numOfNodes+1) + maxPods := *maxENI*(*maxIPPerENI-1) - int32(numOfNodes+1) return maxPods / 2 } diff --git a/test/integration/ipamd/eni_tag_test.go b/test/integration/ipamd/eni_tag_test.go index 661f900c5e..585209ac21 100644 --- a/test/integration/ipamd/eni_tag_test.go +++ b/test/integration/ipamd/eni_tag_test.go @@ -14,6 +14,7 @@ package ipamd import ( + "context" "encoding/json" "fmt" "time" @@ -50,7 +51,7 @@ var _ = Describe("test tags are created on Secondary ENI", func() { time.Sleep(time.Second * 90) By("getting the list of ENIs before setting ADDITIONAL_ENI_TAGS") - instance, err := f.CloudServices.EC2().DescribeInstance(*primaryInstance.InstanceId) + instance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), *primaryInstance.InstanceId) Expect(err).ToNot(HaveOccurred()) existingENIs := make(map[string]bool) @@ -66,7 +67,7 @@ var _ = Describe("test tags are created on Secondary ENI", func() { time.Sleep(time.Second * 90) By("getting the list of current ENIs by describing the instance") - instance, err = f.CloudServices.EC2().DescribeInstance(*primaryInstance.InstanceId) + instance, err = f.CloudServices.EC2().DescribeInstance(context.TODO(), *primaryInstance.InstanceId) Expect(err).ToNot(HaveOccurred()) for _, nwInterface := range instance.NetworkInterfaces { @@ -82,7 +83,7 @@ var _ = Describe("test tags are created on Secondary ENI", func() { JustAfterEach(func() { envVarToRemove := map[string]struct{}{} - for key, _ := range environmentVariables { + for key := range environmentVariables { envVarToRemove[key] = struct{}{} } @@ -137,7 +138,7 @@ var _ = Describe("test tags are created on Secondary ENI", func() { // VerifyTagIsPresentOnENIs verifies that the list of ENIs have expected tag key-val pair func VerifyTagIsPresentOnENIs(newENIIds []string, expectedTags map[string]string) { By(fmt.Sprintf("Describing the list of new ENI created after seeting env variable %v", newENIIds)) - describeNetworkInterfaceOutput, err := f.CloudServices.EC2().DescribeNetworkInterface(newENIIds) + describeNetworkInterfaceOutput, err := f.CloudServices.EC2().DescribeNetworkInterface(context.TODO(), newENIIds) Expect(err).ToNot(HaveOccurred()) By("verifying the new tags are present on new ENIs") diff --git a/test/integration/ipamd/ipamd_event_test.go b/test/integration/ipamd/ipamd_event_test.go index 638cf5c5c5..f896936d82 100644 --- a/test/integration/ipamd/ipamd_event_test.go +++ b/test/integration/ipamd/ipamd_event_test.go @@ -14,6 +14,7 @@ package ipamd import ( + "context" "fmt" "net/url" "os" @@ -22,7 +23,6 @@ import ( k8sUtil "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/utils" "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" - "github.com/aws/aws-sdk-go/aws" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" v1 "k8s.io/api/core/v1" @@ -62,22 +62,22 @@ var _ = Describe("test aws-node pod event", func() { Expect(err).ToNot(HaveOccurred()) instanceID := k8sUtil.GetInstanceIDFromNode(nodeList.Items[0]) - instance, err := f.CloudServices.EC2().DescribeInstance(instanceID) + instance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) Expect(err).ToNot(HaveOccurred()) By("getting the node instance role") instanceProfileRoleName := strings.Split(*instance.IamInstanceProfile.Arn, "instance-profile/")[1] - instanceProfileOutput, err := f.CloudServices.IAM().GetInstanceProfile(instanceProfileRoleName) + instanceProfileOutput, err := f.CloudServices.IAM().GetInstanceProfile(context.TODO(), instanceProfileRoleName) Expect(err).ToNot(HaveOccurred()) role = *instanceProfileOutput.InstanceProfile.Roles[0].RoleName } By("Detaching VPC_CNI policy") - err = f.CloudServices.IAM().DetachRolePolicy(EKSCNIPolicyARN, role) + err = f.CloudServices.IAM().DetachRolePolicy(context.TODO(), EKSCNIPolicyARN, role) Expect(err).ToNot(HaveOccurred()) - masterPolicyName = "masters." + *aws.String(f.Options.ClusterName) - nodePolicyName = "nodes." + *aws.String(f.Options.ClusterName) + masterPolicyName = "masters." + f.Options.ClusterName + nodePolicyName = "nodes." + f.Options.ClusterName dummyPolicyDocumentPath := utils.GetProjectRoot() + DummyPolicyDocument dummyRolePolicyBytes, err := os.ReadFile(dummyPolicyDocumentPath) Expect(err).ToNot(HaveOccurred()) @@ -85,19 +85,19 @@ var _ = Describe("test aws-node pod event", func() { dummyRolePolicyData := string(dummyRolePolicyBytes) // For Kops - clusters have an inline role policy defined and has same role and policy name - rolePolicy, err := f.CloudServices.IAM().GetRolePolicy(nodePolicyName, nodePolicyName) + rolePolicy, err := f.CloudServices.IAM().GetRolePolicy(context.TODO(), nodePolicyName, nodePolicyName) if err == nil { By("Detaching the inline role policy for worker instances") rolePolicyDocumentNode, err = url.QueryUnescape(*rolePolicy.PolicyDocument) - err = f.CloudServices.IAM().PutRolePolicy(dummyRolePolicyData, nodePolicyName, nodePolicyName) + err = f.CloudServices.IAM().PutRolePolicy(context.TODO(), dummyRolePolicyData, nodePolicyName, nodePolicyName) Expect(err).ToNot(HaveOccurred()) } - rolePolicy, err = f.CloudServices.IAM().GetRolePolicy(masterPolicyName, masterPolicyName) + rolePolicy, err = f.CloudServices.IAM().GetRolePolicy(context.TODO(), masterPolicyName, masterPolicyName) if err == nil { By("Detaching the inline role policy for master instances") rolePolicyDocumentMaster, err = url.QueryUnescape(*rolePolicy.PolicyDocument) - err = f.CloudServices.IAM().PutRolePolicy(dummyRolePolicyData, masterPolicyName, masterPolicyName) + err = f.CloudServices.IAM().PutRolePolicy(context.TODO(), dummyRolePolicyData, masterPolicyName, masterPolicyName) Expect(err).ToNot(HaveOccurred()) } @@ -121,18 +121,18 @@ var _ = Describe("test aws-node pod event", func() { AfterEach(func() { By("attaching VPC_CNI policy") - err = f.CloudServices.IAM().AttachRolePolicy(EKSCNIPolicyARN, role) + err = f.CloudServices.IAM().AttachRolePolicy(context.TODO(), EKSCNIPolicyARN, role) Expect(err).ToNot(HaveOccurred()) if rolePolicyDocumentNode != "" { By("Attaching the inline role policy for worker Node") - err = f.CloudServices.IAM().PutRolePolicy(rolePolicyDocumentNode, nodePolicyName, nodePolicyName) + err = f.CloudServices.IAM().PutRolePolicy(context.TODO(), rolePolicyDocumentNode, nodePolicyName, nodePolicyName) Expect(err).ToNot(HaveOccurred()) } if rolePolicyDocumentMaster != "" { By("Attaching the inline role policy for Master Nodes") - err = f.CloudServices.IAM().PutRolePolicy(rolePolicyDocumentNode, masterPolicyName, masterPolicyName) + err = f.CloudServices.IAM().PutRolePolicy(context.TODO(), rolePolicyDocumentNode, masterPolicyName, masterPolicyName) Expect(err).ToNot(HaveOccurred()) } @@ -175,6 +175,6 @@ func RestartAwsNodePods() { podList, err := f.K8sResourceManagers.PodManager().GetPodsWithLabelSelector(AwsNodeLabelKey, utils.AwsNodeName) Expect(err).ToNot(HaveOccurred()) for _, pod := range podList.Items { - f.K8sResourceManagers.PodManager().DeleteAndWaitTillPodDeleted(&pod) + _ = f.K8sResourceManagers.PodManager().DeleteAndWaitTillPodDeleted(&pod) } } diff --git a/test/integration/ipamd/ipamd_suite_test.go b/test/integration/ipamd/ipamd_suite_test.go index 2caca00f83..8f359a452b 100644 --- a/test/integration/ipamd/ipamd_suite_test.go +++ b/test/integration/ipamd/ipamd_suite_test.go @@ -14,6 +14,7 @@ package ipamd import ( + "context" "fmt" "testing" "time" @@ -66,7 +67,7 @@ var _ = BeforeSuite(func() { Expect(primaryNode).To(Not(BeNil()), "expected to find a non-tainted node") fmt.Fprintf(GinkgoWriter, "coredns node is %s\n", primaryNode.Name) instanceID := k8sUtils.GetInstanceIDFromNode(*primaryNode) - primaryInstance, err = f.CloudServices.EC2().DescribeInstance(instanceID) + primaryInstance, err = f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) Expect(err).ToNot(HaveOccurred()) By("getting node with no pods scheduled to run tests") @@ -94,7 +95,7 @@ var _ = BeforeSuite(func() { } fmt.Fprintf(GinkgoWriter, "primary node is %s\n", primaryNode.Name) instanceID = k8sUtils.GetInstanceIDFromNode(*primaryNode) - primaryInstance, err = f.CloudServices.EC2().DescribeInstance(instanceID) + primaryInstance, err = f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) Expect(err).ToNot(HaveOccurred()) // Set default values- WARM_ENI_TARGET to 1, and remove WARM_IP_TARGET, MINIMUM_IP_TARGET and WARM_PREFIX_TARGET diff --git a/test/integration/ipamd/warm_target_test.go b/test/integration/ipamd/warm_target_test.go index 9e5d4ca5b2..a42ef12927 100644 --- a/test/integration/ipamd/warm_target_test.go +++ b/test/integration/ipamd/warm_target_test.go @@ -14,6 +14,7 @@ package ipamd import ( + "context" "strconv" "time" @@ -43,7 +44,7 @@ var _ = Describe("test warm target variables", func() { Eventually(func(g Gomega) { primaryInstance, err = f.CloudServices. - EC2().DescribeInstance(*primaryInstance.InstanceId) + EC2().DescribeInstance(context.TODO(), *primaryInstance.InstanceId) g.Expect(err).ToNot(HaveOccurred()) // Validate number of allocated ENIs @@ -104,7 +105,7 @@ var _ = Describe("test warm target variables", func() { var availIPs int // Query the EC2 Instance to get the list of available IPs on the instance primaryInstance, err = f.CloudServices. - EC2().DescribeInstance(*primaryInstance.InstanceId) + EC2().DescribeInstance(context.TODO(), *primaryInstance.InstanceId) g.Expect(err).ToNot(HaveOccurred()) // Sum all the IPs on all network interfaces minus the primary IPv4 address per ENI diff --git a/test/integration/ipamd/warm_target_test_PD_enabled.go b/test/integration/ipamd/warm_target_test_PD_enabled.go index 59c1ff402d..750df2e8f8 100644 --- a/test/integration/ipamd/warm_target_test_PD_enabled.go +++ b/test/integration/ipamd/warm_target_test_PD_enabled.go @@ -14,9 +14,12 @@ package ipamd import ( + "context" "strconv" "time" + "github.com/aws/aws-sdk-go-v2/aws" + k8sUtils "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/utils" "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" @@ -48,7 +51,7 @@ var _ = Describe("test warm target variables", func() { Eventually(func(g Gomega) { // Query the EC2 Instance to get the list of available Prefixes on the instance primaryInstance, err = f.CloudServices. - EC2().DescribeInstance(*primaryInstance.InstanceId) + EC2().DescribeInstance(context.TODO(), aws.ToString(primaryInstance.InstanceId)) g.Expect(err).ToNot(HaveOccurred()) // Sum all the IPs on all network interfaces minus the primary IPv4 address per ENI @@ -135,7 +138,7 @@ var _ = Describe("test warm target variables", func() { var availPrefixes int // Query the EC2 Instance to get the list of available Prefixes on the instance primaryInstance, err = f.CloudServices. - EC2().DescribeInstance(*primaryInstance.InstanceId) + EC2().DescribeInstance(context.TODO(), aws.ToString(primaryInstance.InstanceId)) g.Expect(err).ToNot(HaveOccurred()) // Sum all the IPs on all network interfaces minus the primary IPv4 address per ENI @@ -187,7 +190,7 @@ var _ = Describe("test warm target variables", func() { // Query the EC2 Instance to get the list of available Prefixes on the instance primaryInstance, err = f.CloudServices. - EC2().DescribeInstance(*primaryInstance.InstanceId) + EC2().DescribeInstance(context.TODO(), aws.ToString(primaryInstance.InstanceId)) Expect(err).ToNot(HaveOccurred()) // Sum all the IPs on all network interfaces minus the primary IPv4 address per ENI diff --git a/test/integration/ipv6/pod_v6_networking_suite_test.go b/test/integration/ipv6/pod_v6_networking_suite_test.go index d51b013e98..6e96786aed 100644 --- a/test/integration/ipv6/pod_v6_networking_suite_test.go +++ b/test/integration/ipv6/pod_v6_networking_suite_test.go @@ -26,8 +26,6 @@ import ( v1 "k8s.io/api/core/v1" ) -const InstanceTypeNodeLabelKey = "beta.kubernetes.io/instance-type" - var primaryNode v1.Node func TestCNIv6PodNetworking(t *testing.T) { @@ -39,8 +37,7 @@ var _ = BeforeSuite(func() { f = framework.New(framework.GlobalOptions) By("creating test namespace") - f.K8sResourceManagers.NamespaceManager(). - CreateNamespace(utils.DefaultTestNamespace) + _ = f.K8sResourceManagers.NamespaceManager().CreateNamespace(utils.DefaultTestNamespace) By(fmt.Sprintf("getting the node with the node label key %s and value %s", f.Options.NgNameLabelKey, f.Options.NgNameLabelVal)) @@ -56,8 +53,7 @@ var _ = BeforeSuite(func() { var _ = AfterSuite(func() { By("deleting test namespace") - f.K8sResourceManagers.NamespaceManager(). - DeleteAndWaitTillNamespaceDeleted(utils.DefaultTestNamespace) + _ = f.K8sResourceManagers.NamespaceManager().DeleteAndWaitTillNamespaceDeleted(utils.DefaultTestNamespace) k8sUtils.UpdateEnvVarOnDaemonSetAndWaitUntilReady(f, "aws-node", "kube-system", "aws-node", map[string]string{ diff --git a/test/integration/metrics-helper/metric_helper_test.go b/test/integration/metrics-helper/metric_helper_test.go index 57e636ddaf..8d608b6ded 100644 --- a/test/integration/metrics-helper/metric_helper_test.go +++ b/test/integration/metrics-helper/metric_helper_test.go @@ -14,6 +14,7 @@ package metrics_helper import ( + "context" "fmt" "math" "time" @@ -21,8 +22,10 @@ import ( "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/manifest" "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudwatch" + cloudwatchtypes "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" v1 "k8s.io/api/apps/v1" @@ -48,7 +51,7 @@ var _ = Describe("test cni-metrics-helper publishes metrics", func() { time.Sleep(time.Minute * 3) getMetricStatisticsInput := &cloudwatch.GetMetricStatisticsInput{ - Dimensions: []*cloudwatch.Dimension{ + Dimensions: []cloudwatchtypes.Dimension{ { Name: aws.String("CLUSTER_ID"), Value: aws.String(ngName), @@ -56,17 +59,17 @@ var _ = Describe("test cni-metrics-helper publishes metrics", func() { }, MetricName: aws.String("addReqCount"), Namespace: aws.String("Kubernetes"), - Period: aws.Int64(int64(30)), - // Start time should sync with when when this test started + Period: aws.Int32(int32(30)), + // Start time should sync with when this test started StartTime: aws.Time(time.Now().Add(time.Duration(-10) * time.Minute)), EndTime: aws.Time(time.Now()), - Statistics: aws.StringSlice([]string{"Maximum"}), + Statistics: []cloudwatchtypes.Statistic{cloudwatchtypes.StatisticMaximum}, } - getMetricOutput, err := f.CloudServices.CloudWatch().GetMetricStatistics(getMetricStatisticsInput) + getMetricOutput, err := f.CloudServices.CloudWatch().GetMetricStatistics(context.TODO(), getMetricStatisticsInput) Expect(err).ToNot(HaveOccurred()) dataPoints := getMetricOutput.Datapoints - fmt.Fprintf(GinkgoWriter, "data points: %+v", dataPoints) + _, _ = fmt.Fprintf(GinkgoWriter, "data points: %+v", dataPoints) By("validating at least 2 metrics are published to CloudWatch") Expect(len(dataPoints)).Should(BeNumerically(">=", 2)) diff --git a/test/integration/metrics-helper/metrics_helper_suite_test.go b/test/integration/metrics-helper/metrics_helper_suite_test.go index 51d2151792..650952d2c6 100644 --- a/test/integration/metrics-helper/metrics_helper_suite_test.go +++ b/test/integration/metrics-helper/metrics_helper_suite_test.go @@ -14,6 +14,7 @@ package metrics_helper import ( + "context" "flag" "fmt" "strings" @@ -73,8 +74,7 @@ var _ = BeforeSuite(func() { f = framework.New(framework.GlobalOptions) By("creating test namespace") - f.K8sResourceManagers.NamespaceManager(). - CreateNamespace(utils.DefaultTestNamespace) + _ = f.K8sResourceManagers.NamespaceManager().CreateNamespace(utils.DefaultTestNamespace) By("getting the node list") nodeList, err := f.K8sResourceManagers.NodeManager().GetNodes(f.Options.NgNameLabelKey, f.Options.NgNameLabelVal) @@ -94,7 +94,7 @@ var _ = BeforeSuite(func() { Expect(instanceID).ToNot(Equal(""), "expected to find a non-tainted node") By("getting the nodegroup name and instance profile") - instance, err := f.CloudServices.EC2().DescribeInstance(instanceID) + instance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) Expect(err).ToNot(HaveOccurred()) instanceTagKeyValuePair := map[string]string{ @@ -119,11 +119,11 @@ var _ = BeforeSuite(func() { if ngName == "" { ngName = DEFAULT_CLUSTER_ID } - fmt.Fprintf(GinkgoWriter, "cluster name: %s\n", ngName) + _, _ = fmt.Fprintf(GinkgoWriter, "cluster name: %s\n", ngName) By("getting the node instance role") instanceProfileRoleName := strings.Split(*instance.IamInstanceProfile.Arn, "instance-profile/")[1] - instanceProfileOutput, err := f.CloudServices.IAM().GetInstanceProfile(instanceProfileRoleName) + instanceProfileOutput, err := f.CloudServices.IAM().GetInstanceProfile(context.TODO(), instanceProfileRoleName) Expect(err).ToNot(HaveOccurred()) ngRoleName = *instanceProfileOutput.InstanceProfile.Roles[0].RoleName @@ -131,7 +131,7 @@ var _ = BeforeSuite(func() { // We should ideally use the PathPrefix argument to list the policy, but this is returning an empty list. So workaround by listing local policies & filter // SO issue: https://stackoverflow.com/questions/66287626/aws-cli-list-policies-to-find-a-policy-with-a-specific-name - policyList, err := f.CloudServices.IAM().ListPolicies("Local") + policyList, err := f.CloudServices.IAM().ListPolicies(context.TODO(), "Local") Expect(err).ToNot(HaveOccurred()) for _, item := range policyList.Policies { @@ -141,7 +141,7 @@ var _ = BeforeSuite(func() { } } - err = f.CloudServices.IAM().AttachRolePolicy(policyARN, ngRoleName) + err = f.CloudServices.IAM().AttachRolePolicy(context.TODO(), policyARN, ngRoleName) Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("unable to attach arn: %s role: %s", policyARN, ngRoleName)) By("updating the aws-nodes to restart the metric count") @@ -162,13 +162,12 @@ var _ = AfterSuite(func() { Expect(err).ToNot(HaveOccurred()) By("detaching role policy from the node IAM Role") - err = f.CloudServices.IAM().DetachRolePolicy(policyARN, ngRoleName) + err = f.CloudServices.IAM().DetachRolePolicy(context.TODO(), policyARN, ngRoleName) Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("unable to detach %s %s", policyARN, ngRoleName)) k8sUtil.RemoveVarFromDaemonSetAndWaitTillUpdated(f, utils.AwsNodeName, utils.AwsNodeNamespace, utils.AwsNodeName, map[string]struct{}{"SOME_NON_EXISTENT_VAR": {}}) By("deleting test namespace") - f.K8sResourceManagers.NamespaceManager(). - DeleteAndWaitTillNamespaceDeleted(utils.DefaultTestNamespace) + _ = f.K8sResourceManagers.NamespaceManager().DeleteAndWaitTillNamespaceDeleted(utils.DefaultTestNamespace) }) diff --git a/test/integration/pod-eni/security_group_per_pod_suite_test.go b/test/integration/pod-eni/security_group_per_pod_suite_test.go index f9430ee9c1..eccfe6db51 100644 --- a/test/integration/pod-eni/security_group_per_pod_suite_test.go +++ b/test/integration/pod-eni/security_group_per_pod_suite_test.go @@ -14,6 +14,7 @@ package pod_eni import ( + "context" "fmt" "testing" @@ -60,13 +61,13 @@ var _ = BeforeSuite(func() { f = framework.New(framework.GlobalOptions) By("checking if cluster address family is IPv4 or IPv6") - clusterOutput, err := f.CloudServices.EKS().DescribeCluster(f.Options.ClusterName) + clusterOutput, err := f.CloudServices.EKS().DescribeCluster(context.TODO(), f.Options.ClusterName) Expect(err).NotTo(HaveOccurred()) - if *clusterOutput.Cluster.KubernetesNetworkConfig.IpFamily == "ipv4" { + if clusterOutput.Cluster.KubernetesNetworkConfig.IpFamily == "ipv4" { isIPv4Cluster = true - fmt.Fprint(GinkgoWriter, "cluster is IPv4\n") + _, _ = fmt.Fprint(GinkgoWriter, "cluster is IPv4\n") } else { - fmt.Fprint(GinkgoWriter, "cluster is IPv6\n") + _, _ = fmt.Fprint(GinkgoWriter, "cluster is IPv6\n") } By("creating a new security group used in Security Group Policy") @@ -76,19 +77,19 @@ var _ = BeforeSuite(func() { } else { sgName = "pod-eni-automation-v6" } - securityGroupOutput, err := f.CloudServices.EC2().CreateSecurityGroup(sgName, + securityGroupOutput, err := f.CloudServices.EC2().CreateSecurityGroup(context.TODO(), sgName, "test created by vpc cni automation test suite", f.Options.AWSVPCID) Expect(err).ToNot(HaveOccurred()) securityGroupId = *securityGroupOutput.GroupId By("authorizing egress and ingress on security group for client-server communication") if isIPv4Cluster { - f.CloudServices.EC2().AuthorizeSecurityGroupEgress(securityGroupId, "tcp", openPort, openPort, v4Zero) - f.CloudServices.EC2().AuthorizeSecurityGroupIngress(securityGroupId, "tcp", openPort, openPort, v4Zero, false) + _ = f.CloudServices.EC2().AuthorizeSecurityGroupEgress(context.TODO(), securityGroupId, "tcp", openPort, openPort, v4Zero) + _ = f.CloudServices.EC2().AuthorizeSecurityGroupIngress(context.TODO(), securityGroupId, "tcp", openPort, openPort, v4Zero, false) } else { - f.CloudServices.EC2().AuthorizeSecurityGroupEgress(securityGroupId, "tcp", openPort, openPort, v6Zero) - f.CloudServices.EC2().AuthorizeSecurityGroupIngress(securityGroupId, "tcp", openPort, openPort, v6Zero, false) - f.CloudServices.EC2().AuthorizeSecurityGroupIngress(securityGroupId, "icmpv6", -1, -1, v6Zero, false) + _ = f.CloudServices.EC2().AuthorizeSecurityGroupEgress(context.TODO(), securityGroupId, "tcp", openPort, openPort, v6Zero) + _ = f.CloudServices.EC2().AuthorizeSecurityGroupIngress(context.TODO(), securityGroupId, "tcp", openPort, openPort, v6Zero, false) + _ = f.CloudServices.EC2().AuthorizeSecurityGroupIngress(context.TODO(), securityGroupId, "icmpv6", -1, -1, v6Zero, false) } By("getting branch ENI limits") @@ -99,12 +100,12 @@ var _ = BeforeSuite(func() { node := nodeList.Items[0] instanceID := k8sUtils.GetInstanceIDFromNode(node) - nodeInstance, err := f.CloudServices.EC2().DescribeInstance(instanceID) - instanceType := *nodeInstance.InstanceType - totalBranchInterface = vpc.Limits[instanceType].BranchInterface * numNodes + nodeInstance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) + instanceType := nodeInstance.InstanceType + totalBranchInterface = vpc.Limits[string(instanceType)].BranchInterface * numNodes By("Getting Cluster Security Group ID") - clusterRes, err := f.CloudServices.EKS().DescribeCluster(f.Options.ClusterName) + clusterRes, err := f.CloudServices.EKS().DescribeCluster(context.TODO(), f.Options.ClusterName) Expect(err).NotTo(HaveOccurred()) clusterSGID = *(clusterRes.Cluster.ResourcesVpcConfig.ClusterSecurityGroupId) fmt.Fprintf(GinkgoWriter, "cluster security group is %s\n", clusterSGID) @@ -137,6 +138,6 @@ var _ = AfterSuite(func() { Expect(err).ToNot(HaveOccurred()) By("deleting the security group") - err = f.CloudServices.EC2().DeleteSecurityGroup(securityGroupId) + err = f.CloudServices.EC2().DeleteSecurityGroup(context.TODO(), securityGroupId) Expect(err).ToNot(HaveOccurred()) }) diff --git a/test/integration/pod-eni/security_group_per_pod_test.go b/test/integration/pod-eni/security_group_per_pod_test.go index 8c92e8a6b5..12e1dc4b24 100644 --- a/test/integration/pod-eni/security_group_per_pod_test.go +++ b/test/integration/pod-eni/security_group_per_pod_test.go @@ -14,6 +14,7 @@ package pod_eni import ( + "context" "encoding/json" "fmt" "time" @@ -57,7 +58,7 @@ var _ = Describe("Security Group for Pods Test", func() { JustBeforeEach(func() { By("creating test namespace") - f.K8sResourceManagers.NamespaceManager(). + _ = f.K8sResourceManagers.NamespaceManager(). CreateNamespace(utils.DefaultTestNamespace) serverDeploymentBuilder = manifest.NewDefaultDeploymentBuilder(). @@ -78,11 +79,11 @@ var _ = Describe("Security Group for Pods Test", func() { JustAfterEach(func() { By("deleting test namespace") - f.K8sResourceManagers.NamespaceManager(). + _ = f.K8sResourceManagers.NamespaceManager(). DeleteAndWaitTillNamespaceDeleted(utils.DefaultTestNamespace) By("Deleting Security Group Policy") - f.K8sResourceManagers.CustomResourceManager().DeleteResource(securityGroupPolicy) + _ = f.K8sResourceManagers.CustomResourceManager().DeleteResource(securityGroupPolicy) By("waiting for the branch ENI to be cooled down") time.Sleep(time.Second * 60) @@ -126,10 +127,10 @@ var _ = Describe("Security Group for Pods Test", func() { // 8080: metric-pod listener port By("Adding an additional Ingress Rule on NodeSecurityGroupID to allow client-to-metric traffic") if isIPv4Cluster { - err := f.CloudServices.EC2().AuthorizeSecurityGroupIngress(clusterSGID, "TCP", metricsPort, metricsPort, v4Zero, false) + err := f.CloudServices.EC2().AuthorizeSecurityGroupIngress(context.TODO(), clusterSGID, "TCP", metricsPort, metricsPort, v4Zero, false) Expect(err).ToNot(HaveOccurred()) } else { - err := f.CloudServices.EC2().AuthorizeSecurityGroupIngress(clusterSGID, "TCP", metricsPort, metricsPort, v6Zero, false) + err := f.CloudServices.EC2().AuthorizeSecurityGroupIngress(context.TODO(), clusterSGID, "TCP", metricsPort, metricsPort, v6Zero, false) Expect(err).ToNot(HaveOccurred()) } }) @@ -160,10 +161,10 @@ var _ = Describe("Security Group for Pods Test", func() { // Revoke the Ingress rule for traffic from client pods added to Node Security Group By("Revoking the additional Ingress rule added to allow client-to-metric traffic") if isIPv4Cluster { - err := f.CloudServices.EC2().RevokeSecurityGroupIngress(clusterSGID, "TCP", metricsPort, metricsPort, v4Zero, false) + err := f.CloudServices.EC2().RevokeSecurityGroupIngress(context.TODO(), clusterSGID, "TCP", metricsPort, metricsPort, v4Zero, false) Expect(err).ToNot(HaveOccurred()) } else { - err := f.CloudServices.EC2().RevokeSecurityGroupIngress(clusterSGID, "TCP", metricsPort, metricsPort, v6Zero, false) + err := f.CloudServices.EC2().RevokeSecurityGroupIngress(context.TODO(), clusterSGID, "TCP", metricsPort, metricsPort, v6Zero, false) Expect(err).ToNot(HaveOccurred()) } }) @@ -247,7 +248,7 @@ var _ = Describe("Security Group for Pods Test", func() { pod, err := f.K8sResourceManagers.PodManager().CreateAndWaitTillRunning(pod) Expect(err).ToNot(HaveOccurred()) - ValidatePodsHaveBranchENI(v1.PodList{Items: []v1.Pod{*pod}}) + _ = ValidatePodsHaveBranchENI(v1.PodList{Items: []v1.Pod{*pod}}) timeAfterLivelinessProbeFails := initialDelay + (periodSecond * failureCount) + 10 @@ -396,7 +397,7 @@ func ValidateHostNetworking(testType TestType, podValidationInputString string) PodLogs(testPod.Namespace, testPod.Name) Expect(errLogs).ToNot(HaveOccurred()) - fmt.Fprintln(GinkgoWriter, logs) + _, _ = fmt.Fprintln(GinkgoWriter, logs) By("deleting the host networking setup pod") err = f.K8sResourceManagers.PodManager(). diff --git a/test/integration/snat/snat_suite_test.go b/test/integration/snat/snat_suite_test.go index 9b09738b44..69dd289d9e 100644 --- a/test/integration/snat/snat_suite_test.go +++ b/test/integration/snat/snat_suite_test.go @@ -1,16 +1,19 @@ package snat import ( + "context" "fmt" "net/url" "path" "strings" "testing" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/amazon-vpc-cni-k8s/test/framework" "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/aws/utils" testUtils "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" - "github.com/aws/aws-sdk-go/service/ec2" + ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" v1 "k8s.io/api/core/v1" @@ -58,7 +61,7 @@ var _ = BeforeSuite(func() { msg := fmt.Sprintf("Creating a keyPair with name: %s if it doesn't exist", DEFAULT_KEY_PAIR) By(msg) - keyPairOutput, _ := f.CloudServices.EC2().DescribeKey(DEFAULT_KEY_PAIR) + keyPairOutput, _ := f.CloudServices.EC2().DescribeKey(context.TODO(), DEFAULT_KEY_PAIR) exists := false if keyPairOutput != nil { @@ -71,17 +74,17 @@ var _ = BeforeSuite(func() { } if exists { - fmt.Fprintln(GinkgoWriter, "KeyPair already exists") + _, _ = fmt.Fprintln(GinkgoWriter, "KeyPair already exists") } else { - fmt.Fprintln(GinkgoWriter, "KeyPair doesn't exist, will be created") - _, err := f.CloudServices.EC2().CreateKey(DEFAULT_KEY_PAIR) + _, _ = fmt.Fprintln(GinkgoWriter, "KeyPair doesn't exist, will be created") + _, err := f.CloudServices.EC2().CreateKey(context.TODO(), DEFAULT_KEY_PAIR) Expect(err).NotTo(HaveOccurred()) } privateSubnetId = vpcConfig.PrivateSubnetList[0] By("Getting Cluster Security Group Id") - out, err := f.CloudServices.EKS().DescribeCluster(f.Options.ClusterName) + out, err := f.CloudServices.EKS().DescribeCluster(context.TODO(), f.Options.ClusterName) Expect(err).NotTo(HaveOccurred()) clusterSecurityGroupId := out.Cluster.ResourcesVpcConfig.ClusterSecurityGroupId @@ -121,20 +124,20 @@ var _ = BeforeSuite(func() { By("Fetching existing Security Groups from the newly created node group instance") - instance, err := f.CloudServices.EC2().DescribeInstance(instanceID) + instance, err := f.CloudServices.EC2().DescribeInstance(context.TODO(), instanceID) Expect(err).NotTo(HaveOccurred()) existingSecurityGroups := instance.SecurityGroups networkInterfaceId := getPrimaryNetworkInterfaceId(instance.NetworkInterfaces, instance.PrivateIpAddress) Expect(networkInterfaceId).NotTo(Equal(BeNil())) - securityGroupIds := make([]*string, 0, len(existingSecurityGroups)+1) + securityGroupIds := make([]string, 0, len(existingSecurityGroups)+1) for _, sg := range existingSecurityGroups { - securityGroupIds = append(securityGroupIds, sg.GroupId) + securityGroupIds = append(securityGroupIds, aws.ToString(sg.GroupId)) } - securityGroupIds = append(securityGroupIds, clusterSecurityGroupId) + securityGroupIds = append(securityGroupIds, aws.ToString(clusterSecurityGroupId)) By("Adding ClusterSecurityGroup to the new nodegroup Instance") - _, err = f.CloudServices.EC2().ModifyNetworkInterfaceSecurityGroups(securityGroupIds, networkInterfaceId) + _, err = f.CloudServices.EC2().ModifyNetworkInterfaceSecurityGroups(context.TODO(), securityGroupIds, networkInterfaceId) Expect(err).NotTo(HaveOccurred()) }) @@ -142,7 +145,7 @@ var _ = AfterSuite(func() { //using default key pair created by test if DEFAULT_KEY_PAIR == "test-key-pair" { By("Deleting key-pair") - err := f.CloudServices.EC2().DeleteKey(DEFAULT_KEY_PAIR) + err := f.CloudServices.EC2().DeleteKey(context.TODO(), DEFAULT_KEY_PAIR) Expect(err).NotTo(HaveOccurred()) } @@ -155,7 +158,7 @@ var _ = AfterSuite(func() { Expect(err).NotTo(HaveOccurred()) }) -func getPrimaryNetworkInterfaceId(networkInterfaces []*ec2.InstanceNetworkInterface, instanceIPAddr *string) *string { +func getPrimaryNetworkInterfaceId(networkInterfaces []ec2types.InstanceNetworkInterface, instanceIPAddr *string) *string { for _, ni := range networkInterfaces { if strings.Compare(*ni.PrivateIpAddress, *instanceIPAddr) == 0 { return ni.NetworkInterfaceId diff --git a/test/integration/snat/snat_test.go b/test/integration/snat/snat_test.go index f95b6854f6..e78e53f851 100644 --- a/test/integration/snat/snat_test.go +++ b/test/integration/snat/snat_test.go @@ -1,21 +1,20 @@ package snat import ( + "context" "fmt" "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/manifest" k8sUtils "github.com/aws/amazon-vpc-cni-k8s/test/framework/resources/k8s/utils" "github.com/aws/amazon-vpc-cni-k8s/test/framework/utils" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" ) const ( - TEST_POD_LABEL_KEY = "test-pod-label-key" - TEST_POD_LABEL_VALUE = "test-pod-label-val" - EXTERNAL_DOMAIN = "https://aws.amazon.com/" + EXTERNAL_DOMAIN = "https://aws.amazon.com/" ) var _ = Describe("SNAT tests", func() { @@ -47,13 +46,13 @@ var _ = Describe("SNAT tests", func() { Context("Validate AWS_VPC_K8S_CNI_RANDOMIZESNAT", func() { It("Verify SNAT IP table rule by changing AWS_VPC_K8S_CNI_RANDOMIZESNAT", func() { - vpcOutput, err := f.CloudServices.EC2().DescribeVPC(f.Options.AWSVPCID) + vpcOutput, err := f.CloudServices.EC2().DescribeVPC(context.TODO(), f.Options.AWSVPCID) Expect(err).NotTo(HaveOccurred()) Expect(len(vpcOutput.Vpcs)).To(BeNumerically(">", 0)) numOfCidrs := 0 for _, vpc := range vpcOutput.Vpcs[0].CidrBlockAssociationSet { - if *vpc.CidrBlockState.State == "associated" { + if vpc.CidrBlockState.State == "associated" { numOfCidrs = numOfCidrs + 1 } } @@ -74,14 +73,14 @@ var _ = Describe("SNAT tests", func() { Context("Validate AWS_VPC_K8S_CNI_EXCLUDE_SNAT_CIDRS", func() { It("Verify External Domain Connectivity by modifying AWS_VPC_K8S_CNI_EXCLUDE_SNAT_CIDRS", func() { By("Getting CIDR for primary node's private subnet") - out, err := f.CloudServices.EC2().DescribeSubnet(privateSubnetId) + out, err := f.CloudServices.EC2().DescribeSubnet(context.TODO(), privateSubnetId) Expect(err).NotTo(HaveOccurred()) Expect(len(out.Subnets)).To(BeNumerically(">", 0)) cidrBlock := out.Subnets[0].CidrBlock By("Updating AWS_VPC_K8S_CNI_EXCLUDE_SNAT_CIDRS with private subnet CIDR") k8sUtils.AddEnvVarToDaemonSetAndWaitTillUpdated(f, utils.AwsNodeName, utils.AwsNodeNamespace, utils.AwsNodeName, map[string]string{ - "AWS_VPC_K8S_CNI_EXCLUDE_SNAT_CIDRS": aws.StringValue(cidrBlock), + "AWS_VPC_K8S_CNI_EXCLUDE_SNAT_CIDRS": aws.ToString(cidrBlock), }) By("Check External domain connectivity from this private subnet CIDR block") @@ -127,7 +126,7 @@ func ValidateExternalDomainConnectivity(url string) { PodLogs(testPod.Namespace, testPod.Name) Expect(errLogs).ToNot(HaveOccurred()) - fmt.Fprintln(GinkgoWriter, logs) + _, _ = fmt.Fprintln(GinkgoWriter, logs) By("deleting the test pod") err = f.K8sResourceManagers.PodManager(). @@ -167,7 +166,7 @@ func ValidateIPTableRules(randomizedSNATValue string, numOfCidrs int) { PodLogs(hostNetworkPod.Namespace, hostNetworkPod.Name) Expect(errLogs).ToNot(HaveOccurred()) - fmt.Fprintln(GinkgoWriter, logs) + _, _ = fmt.Fprintln(GinkgoWriter, logs) By("deleting the host networking setup pod") err = f.K8sResourceManagers.PodManager(). diff --git a/utils/imds/imds.go b/utils/imds/imds.go index 92a77be604..c10f022277 100644 --- a/utils/imds/imds.go +++ b/utils/imds/imds.go @@ -1,28 +1,36 @@ package imds import ( + "context" "fmt" + "io" - "github.com/aws/aws-sdk-go/aws" - ec2metadatasvc "github.com/aws/aws-sdk-go/aws/ec2metadata" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" ) // EC2Metadata wraps the methods from the amazon-sdk-go's ec2metadata package -type EC2Metadata interface { - GetMetadata(path string) (string, error) - Region() (string, error) -} +// type EC2Metadata interface { +// GetMetadata(path string) (string, error) +// Region() (string, error) +// } func GetMetaData(key string) (string, error) { - awsSession := session.Must(session.NewSession(aws.NewConfig(). - WithMaxRetries(10), - )) - var ec2Metadata EC2Metadata - ec2Metadata = ec2metadatasvc.New(awsSession) - requestedData, err := ec2Metadata.GetMetadata(key) + cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRetryMaxAttempts(10)) + if err != nil { + return "", fmt.Errorf("unable to load SDK config, %v", err) + } + + client := imds.NewFromConfig(cfg) + requestedData, err := client.GetMetadata(context.TODO(), &imds.GetMetadataInput{ + Path: key, + }) if err != nil { return "", fmt.Errorf("get instance metadata: failed to retrieve %s - %s", key, err) } - return requestedData, nil + content, err := io.ReadAll(requestedData.Content) + if err != nil { + return "", fmt.Errorf("get instance metadata: failed to read %s - %s", key, err) + } + return string(content), nil }